Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct LuaSignature {
pub param_docs: HashMap<usize, LuaDocParamInfo>,
pub params: Vec<String>,
pub return_docs: Vec<LuaDocReturnInfo>,
/// 当没有返回值注解且返回了值时, 该值有可能为`true`, 如果有返回值注解, 那么一定为`false`
pub(crate) resolve_return: bool,
pub is_colon_define: bool,
}
Expand Down Expand Up @@ -87,9 +88,8 @@ impl LuaSignature {

// `field`定义的`function`也被视为`signature`
pub fn first_param_is_self(&self) -> bool {
self.get_param_info_by_id(0).map_or(false, |info| {
info.type_ref.is_self_infer()
})
self.get_param_info_by_id(0)
.map_or(false, |info| info.type_ref.is_self_infer())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ fn check_return_stat(
let signature = context.db.get_signature_index().get(&signature_id)?;
let return_types = signature.get_return_types();

// 如果没有返回值注解, 则不检查
if signature.resolve_return || return_types.is_empty() {
return Some(());
}

let disable_return_count_check = return_types.iter().any(|ty| ty.is_variadic());

let expr_return_len = return_stat.get_expr_list().collect::<Vec<_>>().len();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::ops::Deref;

use emmylua_parser::{LuaAst, LuaAstNode, LuaAstToken, LuaCallExpr, LuaExpr, LuaIndexToken};
use emmylua_parser::{LuaAst, LuaAstNode, LuaAstToken, LuaCallExpr, LuaExpr};
use rowan::TextRange;

use crate::{
humanize_type, DiagnosticCode, LuaMultiReturn, LuaType, RenderLevel, SemanticModel,
TypeCheckFailReason, TypeCheckResult,
can_colon_call, humanize_type, DiagnosticCode, LuaMultiReturn, LuaType, RenderLevel,
SemanticModel, TypeCheckFailReason, TypeCheckResult,
};

use super::DiagnosticContext;
Expand Down Expand Up @@ -51,20 +51,17 @@ fn check_call_expr(
(true, false) => {
args.insert(0, None);

if let Some((_, Some(t))) = params.first() {
if !matches!(t, LuaType::SelfInfer | LuaType::Any) {
if let Some(prefix_expr) = call_expr.get_prefix_expr() {
if let Some(colon_token) = prefix_expr.token::<LuaIndexToken>() {
add_type_check_diagnostic(
context,
semantic_model,
colon_token.get_range(),
t,
&LuaType::SelfInfer,
Err(TypeCheckFailReason::TypeNotMatch),
);
}
}
if let Some((_, Some(self_type))) = params.first() {
let result = can_colon_call(semantic_model, call_expr.clone(), self_type);
if !result.is_ok() {
add_type_check_diagnostic(
context,
semantic_model,
call_expr.get_colon_token()?.get_range(),
self_type,
&LuaType::SelfInfer,
result,
);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ fn check_return_stat(
let signature_id = LuaSignatureId::from_closure(semantic_model.get_file_id(), &closure_expr);
let signature = context.db.get_signature_index().get(&signature_id)?;
let return_types = signature.get_return_types();

// 如果没有返回值注解, 则不检查
if signature.resolve_return || return_types.is_empty() {
return Some(());
}
let disable_return_count_check = return_types.iter().any(|ty| ty.is_variadic());
let expr_return_len = return_stat.get_expr_list().collect::<Vec<_>>().len();
let return_types_len = return_types.len();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ fn check_return_stat(
let signature_id = LuaSignatureId::from_closure(semantic_model.get_file_id(), &closure_expr);
let signature = context.db.get_signature_index().get(&signature_id)?;
let return_types = signature.get_return_types();

// 如果没有返回值注解, 则不检查
if signature.resolve_return || return_types.is_empty() {
return Some(());
}
for (index, expr) in return_stat.get_expr_list().enumerate() {
let return_type = return_types.get(index).unwrap_or(&LuaType::Any);
if let LuaType::Variadic(variadic) = return_type {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ mod test {
function mergeInto(target, ...)
-- Stuff
end
"#);

"#,
);

assert!(!ws.check_code_for(
DiagnosticCode::ParamTypeNotMatch,
Expand Down Expand Up @@ -273,4 +273,15 @@ mod test {
));
}

#[test]
fn test_issue_148() {
let mut ws = VirtualWorkspace::new_with_init_std_lib();

assert!(ws.check_code_for(
DiagnosticCode::ParamTypeNotMatch,
r#"
local a = (''):format()
"#
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,30 @@ mod tests {
"#
));
}

#[test]
fn test_not_return_anno() {
let mut ws = VirtualWorkspace::new();

assert!(ws.check_code_for(
DiagnosticCode::MissingReturnValue,
r#"
local function baz()
if true then
return
end
return 1
end
"#
));

assert!(ws.check_code_for(
DiagnosticCode::RedundantReturnValue,
r#"
function bar(a)
return tonumber(a)
end
"#
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ mod tests {
));
}


#[test]
fn test_variadic_return_type_mismatch() {
let mut ws = VirtualWorkspace::new();
Expand All @@ -73,4 +72,38 @@ mod tests {
));
}

#[test]
fn test_issue_146() {
let mut ws = VirtualWorkspace::new();

assert!(ws.check_code_for(
DiagnosticCode::ReturnTypeMismatch,
r#"
local function bar()
return {}
end

---@param _f fun():table 测试
function foo(_f) end

foo(function()
return bar()
end)
"#
));
}

#[test]
fn test_issue_150() {
let mut ws = VirtualWorkspace::new();

assert!(ws.check_code_for(
DiagnosticCode::RedundantReturnValue,
r#"
function bar(a)
return tonumber(a)
end
"#
));
}
}
2 changes: 1 addition & 1 deletion crates/emmylua_code_analysis/src/semantic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use semantic_info::{
infer_node_property_owner, infer_node_semantic_info, infer_token_property_owner,
infer_token_semantic_info,
};
pub(crate) use type_check::check_type_compact;
pub(crate) use type_check::{check_type_compact, can_colon_call};
use type_check::is_sub_type_of;
use visibility::check_visibility;

Expand Down
53 changes: 39 additions & 14 deletions crates/emmylua_code_analysis/src/semantic/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ mod generic_type;
mod ref_type;
mod simple_type;
mod sub_type;
mod test;
mod type_check_fail_reason;
mod type_check_guard;
mod test;

use complex_type::check_complex_type_compact;
use emmylua_parser::{LuaAstNode, LuaCallExpr, LuaExpr, LuaIndexToken};
use func_type::{check_doc_func_type_compact, check_sig_type_compact};
use generic_type::check_generic_type_compact;
use ref_type::check_ref_type_compact;
Expand All @@ -22,6 +23,8 @@ use crate::{
};
pub use sub_type::is_sub_type_of;

use super::SemanticModel;

pub type TypeCheckResult = Result<(), TypeCheckFailReason>;

pub fn check_type_compact(
Expand All @@ -32,6 +35,36 @@ pub fn check_type_compact(
check_general_type_compact(db, source, compact_type, TypeCheckGuard::new())
}

/// 检查是否可以进行冒号调用, 必须是冒号调用且非冒号定义的情况下才能检查
pub fn can_colon_call(
semantic_model: &SemanticModel,
call_expr: LuaCallExpr,
self_type: &LuaType,
) -> TypeCheckResult {
if !matches!(self_type, LuaType::SelfInfer | LuaType::Any) {
if let Some(prefix_expr) = call_expr.get_prefix_expr() {
if let Some(_) = prefix_expr.token::<LuaIndexToken>() {
// 我们需要将 `SelfInfer` 缩小为实际类型
let result = match prefix_expr {
LuaExpr::IndexExpr(index_expr) => {
if let Some(prefix_expr) = index_expr.get_prefix_expr() {
let expr_type = semantic_model
.infer_expr(prefix_expr.clone())
.unwrap_or(LuaType::SelfInfer);
semantic_model.type_check(self_type, &expr_type)
} else {
Err(TypeCheckFailReason::TypeNotMatch)
}
}
_ => Err(TypeCheckFailReason::TypeNotMatch),
};
return result;
}
}
}
Ok(())
}

fn check_general_type_compact(
db: &DbIndex,
source: &LuaType,
Expand All @@ -43,12 +76,7 @@ fn check_general_type_compact(
}

if let Some(origin_type) = escape_type(db, compact_type) {
return check_general_type_compact(
db,
source,
&origin_type,
check_guard.next_level()?,
);
return check_general_type_compact(db, source, &origin_type, check_guard.next_level()?);
}

match source {
Expand Down Expand Up @@ -91,10 +119,8 @@ fn check_general_type_compact(
LuaType::DocFunction(doc_func) => {
check_doc_func_type_compact(db, doc_func, compact_type, check_guard)
}
// signature type
LuaType::Signature(sig_id) => {
check_sig_type_compact(db, sig_id, compact_type, check_guard)
},
// signature type
LuaType::Signature(sig_id) => check_sig_type_compact(db, sig_id, compact_type, check_guard),

// complex type
LuaType::Array(_)
Expand All @@ -103,9 +129,8 @@ fn check_general_type_compact(
| LuaType::Object(_)
| LuaType::Union(_)
| LuaType::Intersection(_)
| LuaType::TableGeneric(_)
| LuaType::MultiLineUnion(_)
=> {
| LuaType::TableGeneric(_)
| LuaType::MultiLineUnion(_) => {
check_complex_type_compact(db, source, compact_type, check_guard)
}

Expand Down
22 changes: 12 additions & 10 deletions crates/emmylua_parser/src/syntax/node/lua/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use crate::{
LuaAstToken, LuaIndexToken, LuaLiteralToken, LuaSyntaxNode, LuaSyntaxToken, LuaTokenKind,
};

use super::{path_trait::PathTrait, LuaBlock, LuaCallArgList, LuaIndexKey, LuaParamList, LuaTableField};
use super::{
path_trait::PathTrait, LuaBlock, LuaCallArgList, LuaIndexKey, LuaParamList, LuaTableField,
};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum LuaExpr {
Expand Down Expand Up @@ -320,7 +322,6 @@ impl LuaIndexExpr {
}
}


impl PathTrait for LuaIndexExpr {}

impl From<LuaIndexExpr> for LuaVarExpr {
Expand Down Expand Up @@ -372,17 +373,18 @@ impl LuaCallExpr {
}

pub fn is_colon_call(&self) -> bool {
let prefix = self.get_prefix_expr();
if let Some(prefix) = prefix {
if let LuaExpr::IndexExpr(index_expr) = prefix {
if let Some(index_token) = index_expr.get_index_token() {
return index_token.is_colon();
}
}
if let Some(index_token) = self.get_colon_token() {
return index_token.is_colon();
}

return false;
}

pub fn get_colon_token(&self) -> Option<LuaIndexToken> {
self.get_prefix_expr().and_then(|prefix| match prefix {
LuaExpr::IndexExpr(index_expr) => index_expr.get_index_token(),
_ => None,
})
}
}

impl PathTrait for LuaCallExpr {}
Expand Down