From bdb72acbc11d6a2e50f38fa15ca04ec74af44200 Mon Sep 17 00:00:00 2001 From: ShenzhenGopher Date: Thu, 11 Jun 2026 09:14:47 +0000 Subject: [PATCH] [FIX] fix false undefined-field for table when value type is generic and key is not string/integer When a table field has a generic value type (e.g. Box?) and the key type K is not string or integer (e.g. thread, boolean), indexing the table with a correctly-typed key falsely reports undefined-field. Root cause: get_key_types() only recognized string, integer and a few other types, silently dropping thread/boolean/number/userdata. The subsequent ExprType member matching also only handled string and integer. Fix: - Add thread/boolean/number/userdata to get_key_types() - Add fallback equality check in ExprType matching branch - Add test cases for thread and boolean key types --- .../src/diagnostic/checker/check_field.rs | 5 +++ .../diagnostic/test/undefined_field_test.rs | 44 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/crates/emmylua_code_analysis/src/diagnostic/checker/check_field.rs b/crates/emmylua_code_analysis/src/diagnostic/checker/check_field.rs index 47d22a516..df25bc6ad 100644 --- a/crates/emmylua_code_analysis/src/diagnostic/checker/check_field.rs +++ b/crates/emmylua_code_analysis/src/diagnostic/checker/check_field.rs @@ -274,6 +274,8 @@ pub(super) fn is_valid_member( } } else if typ.is_integer() && key_types.iter().any(|typ| typ.is_integer()) { return Some(()); + } else if key_types.iter().any(|kt| kt == typ) { + return Some(()); } } LuaMemberKey::Name(_) => { @@ -378,6 +380,9 @@ fn get_key_types(db: &DbIndex, typ: &LuaType) -> HashSet { LuaType::DocStringConst(_) | LuaType::DocIntegerConst(_) => { type_set.insert(current_type); } + LuaType::Boolean | LuaType::Thread | LuaType::Number | LuaType::Userdata => { + type_set.insert(current_type); + } LuaType::Call(alias_call) => { if let Some(key_types) = get_keyof_keys(db, alias_call) { for t in key_types { diff --git a/crates/emmylua_code_analysis/src/diagnostic/test/undefined_field_test.rs b/crates/emmylua_code_analysis/src/diagnostic/test/undefined_field_test.rs index cfefece06..b380f6d2d 100644 --- a/crates/emmylua_code_analysis/src/diagnostic/test/undefined_field_test.rs +++ b/crates/emmylua_code_analysis/src/diagnostic/test/undefined_field_test.rs @@ -900,4 +900,48 @@ mod test { assert_eq!(ws.expr_ty("alias_result"), ws.ty("string?")); assert_eq!(ws.expr_ty("numeric_result"), ws.ty("string?")); } + + #[test] + fn test_table_generic_value_with_thread_key() { + let mut ws = VirtualWorkspace::new(); + assert!(ws.has_no_diagnostic( + DiagnosticCode::UndefinedField, + r#" + ---@class Box + ---@field value T + + ---@class Container + ---@field items table?> + local Container = {} + + ---@param co thread + function Container:get(co) + local item = self.items[co] + return item + end + "# + )); + } + + #[test] + fn test_table_generic_value_with_boolean_key() { + let mut ws = VirtualWorkspace::new(); + assert!(ws.has_no_diagnostic( + DiagnosticCode::UndefinedField, + r#" + ---@class Box + ---@field value T + + ---@class Container + ---@field items table?> + local Container = {} + + ---@param key boolean + function Container:get(key) + local item = self.items[key] + return item + end + "# + )); + } }