Skip to content
Draft

update #1161

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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
dhat-heap.json

# AI
.agents
.cursor
.claude
.codex
openspec
.trellis
AGENTS.md
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

*All notable changes to the EmmyLua Analyzer Rust project will be documented in this file.*

## [Unreleased]

### 🗑️ Removed

- **`lsp_optimization`**: Removed the `skip_table_fields_check` optimization (including the old `check_table_field` alias). Table field diagnostics are no longer skipped via this attribute.

## [0.24.0] - 2026-7-10

### ✨ Added
Expand Down
3 changes: 1 addition & 2 deletions crates/emmylua_code_analysis/resources/std/builtin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,10 @@
--- Language Server Optimization Items.
---
--- Parameters:
--- - `skip_table_fields_check`: Skip table field diagnostics. It is recommended to use this option for all large configuration tables.
--- - `delayed_definition`: Indicates that the type of the variable is determined by the first assignment.
--- Only valid for `local` declarations with no initial value.
--- @class lsp_optimization: Attribute
--- @overload fun(code: "skip_table_fields_check"|"delayed_definition")
--- @overload fun(code: "delayed_definition")

---
--- Index field alias, will be displayed in `hint` and `completion`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ pub fn analyze_param(analyzer: &mut DocAnalyzer, tag: LuaDocTagParam) -> Option<
.get_db()
.get_signature_index_mut()
.get_or_create(id);
signature.has_explicit_docs = true;
let param_info = LuaDocParamInfo {
name: name.clone(),
type_ref: type_ref.clone(),
Expand Down Expand Up @@ -261,6 +262,7 @@ pub fn analyze_return(analyzer: &mut DocAnalyzer, tag: LuaDocTagReturn) -> Optio
.collect::<Vec<_>>();

bind_signature_return_docs(analyzer, &tag, |signature| {
signature.has_explicit_docs = true;
signature.return_docs.extend(return_infos);
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use smol_str::SmolStr;

use crate::{
InFiled, InferFailReason, InferGuardRef, LuaInferCache, LuaInstanceType, LuaMemberId,
LuaMemberOwner, LuaOperatorOwner, TypeOps, TypeSubstitutor, check_type_compact,
LuaMemberOwner, LuaOperatorOwner, TypeOps, TypeSubstitutor,
db_index::{
DbIndex, LuaGenericType, LuaIntersectionType, LuaMemberKey, LuaObjectType,
LuaOperatorMetaMethod, LuaTupleType, LuaType, LuaTypeDeclId, LuaUnionType,
},
infer_expr, instantiate_type_generic,
infer_expr, instantiate_type_generic, is_assignable,
semantic::InferGuard,
};

Expand Down Expand Up @@ -316,7 +316,7 @@ fn find_index_metamethod(
LuaIndexKey::Expr(expr) => infer_expr(db, cache, expr.clone())?,
};

if check_type_compact(db, key_type, &access_key_type).is_ok() {
if is_assignable(db, &access_key_type, key_type) {
return Ok(value_type.clone());
}

Expand Down Expand Up @@ -548,7 +548,7 @@ fn find_member_by_index_table(
LuaMemberKey::Integer(i) => LuaType::IntegerConst(*i),
_ => continue,
};
if check_type_compact(db, &key_type, &member_key_type).is_ok() {
if is_assignable(db, &member_key_type, &key_type) {
let member_type = db
.get_type_index()
.get_type_cache(&member.get_id().into())
Expand Down Expand Up @@ -663,7 +663,7 @@ fn infer_member_by_index_array(
} else if member_key.is_expr() {
let expr = member_key.get_expr().ok_or(InferFailReason::None)?;
let expr_type = infer_expr(db, cache, expr.clone())?;
if check_type_compact(db, &LuaType::Number, &expr_type).is_ok() {
if is_assignable(db, &expr_type, &LuaType::Number) {
return Ok(base.clone());
}
}
Expand All @@ -683,7 +683,7 @@ fn infer_member_by_index_object(
let expr = member_key.get_expr().ok_or(InferFailReason::None)?;
let expr_type = infer_expr(db, cache, expr.clone())?;
for (key, field) in access_member_type {
if check_type_compact(db, key, &expr_type).is_ok() {
if is_assignable(db, &expr_type, key) {
return Ok(field.clone());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,6 @@ mod test {
assert_eq!(ws.humanize_type(ty), "A");
}

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

ws.has_no_diagnostic(
DiagnosticCode::AssignTypeMismatch,
r#"
---@[lsp_optimization("skip_table_fields_check")]
local config = {}
"#,
);
}

#[test]
fn test_attribute_overload_uses_arg_type_for_diagnostic() {
let mut ws = VirtualWorkspace::new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ mod test {
let ty = ws.expr_ty("result");
let expected = ws.ty("integer");
let nil = ws.ty("nil");
assert!(ws.check_type(&ty, &expected));
assert!(!ws.check_type(&ty, &nil));
assert!(ws.check_type(&expected, &ty));
assert!(!ws.check_type(&nil, &ty));
}

#[test]
Expand Down Expand Up @@ -364,8 +364,8 @@ mod test {
let ty = ws.expr_ty("result");
let expected = ws.ty("integer|string");
let nil = ws.ty("nil");
assert!(ws.check_type(&ty, &expected));
assert!(!ws.check_type(&ty, &nil));
assert!(ws.check_type(&expected, &ty));
assert!(!ws.check_type(&nil, &ty));
}

#[test]
Expand Down Expand Up @@ -393,7 +393,7 @@ mod test {
let ty = ws.expr_ty("result");
let expected = ws.ty("integer|string");
let nil = ws.ty("nil");
assert!(ws.check_type(&ty, &expected));
assert!(!ws.check_type(&ty, &nil));
assert!(ws.check_type(&expected, &ty));
assert!(!ws.check_type(&nil, &ty));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ mod test {

let result_ty = ws.expr_ty("Result");
let expected_ty = ws.ty("string?");
assert!(ws.check_type(&result_ty, &expected_ty));
assert!(ws.check_type(&expected_ty, &result_ty));
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ mod test {
let ty = ws.expr_ty(r#"require("virtual_0")"#);
let integer = ws.ty("integer");
let nil = ws.ty("nil");
assert!(ws.check_type(&ty, &integer));
assert!(!ws.check_type(&ty, &nil));
assert!(ws.check_type(&integer, &ty));
assert!(!ws.check_type(&nil, &ty));
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,17 +161,17 @@ mod test {

let status_ty = ws.expr_ty("status");
let boolean_ty = ws.ty("boolean");
assert!(ws.check_type(&status_ty, &boolean_ty));
assert!(ws.check_type(&boolean_ty, &status_ty));
assert!(!status_ty.is_always_truthy());
assert!(!status_ty.is_always_falsy());

let value_ty = ws.expr_ty("value");
let integer_or_string_ty = ws.ty("integer|string");
let integer_ty = ws.ty("integer");
let string_ty = ws.ty("string");
assert!(ws.check_type(&value_ty, &integer_or_string_ty));
assert!(ws.check_type(&value_ty, &integer_ty));
assert!(ws.check_type(&value_ty, &string_ty));
assert!(ws.check_type(&integer_or_string_ty, &value_ty));
assert!(ws.check_type(&integer_ty, &value_ty));
assert!(ws.check_type(&string_ty, &value_ty));
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ impl LuaOwnerMembers {
self.members.values()
}

pub fn iter(&self) -> impl Iterator<Item = (&LuaMemberKey, &LuaMemberIndexItem)> {
self.members.iter()
}

pub fn iter_mut(&mut self) -> impl Iterator<Item = (&LuaMemberKey, &mut LuaMemberIndexItem)> {
self.members.iter_mut()
}
Expand Down
8 changes: 7 additions & 1 deletion crates/emmylua_code_analysis/src/db_index/member/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,13 @@ impl LuaMemberIndex {
Some(members)
}

#[allow(unused)]
pub fn get_member_items(
&self,
owner: &LuaMemberOwner,
) -> Option<impl Iterator<Item = (&LuaMemberKey, &LuaMemberIndexItem)>> {
Some(self.owner_members.get(owner)?.iter())
}

pub fn get_member_item_by_member_id(
&self,
member_id: LuaMemberId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,6 @@ impl LuaAttributeUse {
}

let code = match self.get_string_param("code")? {
"skip_table_fields_check" | "check_table_field" => {
LuaLspOptimizationCode::SkipTableFieldsCheck
}
"delayed_definition" => LuaLspOptimizationCode::DelayedDefinition,
_ => return None,
};
Expand Down Expand Up @@ -252,14 +249,12 @@ pub struct LuaDeprecatedAttribute<'a> {

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LuaLspOptimizationCode {
SkipTableFieldsCheck,
DelayedDefinition,
}

impl LuaLspOptimizationCode {
pub const fn as_str(self) -> &'static str {
match self {
Self::SkipTableFieldsCheck => "skip_table_fields_check",
Self::DelayedDefinition => "delayed_definition",
}
}
Expand All @@ -271,10 +266,6 @@ pub struct LuaLspOptimizationAttribute {
}

impl LuaLspOptimizationAttribute {
pub fn is_skip_table_fields_check(self) -> bool {
self.code == LuaLspOptimizationCode::SkipTableFieldsCheck
}

pub fn is_delayed_definition(self) -> bool {
self.code == LuaLspOptimizationCode::DelayedDefinition
}
Expand Down Expand Up @@ -408,20 +399,4 @@ mod tests {
LuaLspOptimizationCode::DelayedDefinition
);
}

#[test]
fn lsp_optimization_accepts_skip_table_fields_check_aliases() {
for code in ["skip_table_fields_check", "check_table_field"] {
let attribute = LuaAttributeUse::new(
LuaTypeDeclId::global("lsp_optimization"),
vec![("code".into(), Some(doc_string(code)))],
);

let lsp_optimization = attribute.as_lsp_optimization().unwrap();
assert_eq!(
lsp_optimization.code,
LuaLspOptimizationCode::SkipTableFieldsCheck
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::{
pub struct LuaSignature {
pub generic_params: Vec<GenericParam>,
pub overloads: Vec<Arc<LuaFunctionType>>,
pub has_explicit_docs: bool,
pub param_docs: HashMap<usize, LuaDocParamInfo>,
pub params: Vec<String>,
pub return_docs: Vec<LuaDocReturnInfo>,
Expand Down Expand Up @@ -49,6 +50,7 @@ impl LuaSignature {
Self {
generic_params: Vec::new(),
overloads: Vec::new(),
has_explicit_docs: false,
param_docs: HashMap::new(),
params: Vec::new(),
return_docs: Vec::new(),
Expand Down Expand Up @@ -151,9 +153,7 @@ impl LuaSignature {
return false;
}

semantic_model
.type_check(owner_type, &param_info.type_ref)
.is_ok()
semantic_model.is_assignable(&param_info.type_ref, owner_type)
}
None => param_info.name == "self",
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,10 @@ impl LuaFunctionType {
{
return false;
}
if semantic_model.type_check(owner_type, t).is_ok() {
if semantic_model.is_assignable(t, owner_type) {
return true;
}
name == "self" && semantic_model.type_check(t, owner_type).is_ok()
name == "self" && semantic_model.is_assignable(owner_type, t)
}
None => name == "self",
}
Expand Down
Loading