diff --git a/crates/emmylua_code_analysis/src/compilation/test/flow.rs b/crates/emmylua_code_analysis/src/compilation/test/flow.rs index 34bae9ae..0a87b6dd 100644 --- a/crates/emmylua_code_analysis/src/compilation/test/flow.rs +++ b/crates/emmylua_code_analysis/src/compilation/test/flow.rs @@ -1,6 +1,5 @@ #[cfg(test)] mod test { - use crate::{DiagnosticCode, LuaType, VirtualWorkspace}; #[test] @@ -1174,8 +1173,25 @@ end end "#, ); - let a = ws.expr_ty("A"); - assert_eq!(ws.humanize_type(a), "T"); + + // Note: we can't use `ws.ty_expr("A")` to get a true type of `A` + // because `infer_global_type` will not allow generic variables + // from `bindGC` to escape into global space. + let db = &ws.analysis.compilation.db; + let decl_id = db + .get_global_index() + .get_global_decl_ids("A") + .unwrap() + .first() + .unwrap() + .clone(); + let typ = db + .get_type_index() + .get_type_cache(&decl_id.into()) + .unwrap() + .as_type(); + + assert_eq!(ws.humanize_type(typ.clone()), "T"); } #[test] diff --git a/crates/emmylua_code_analysis/src/compilation/test/generic_test.rs b/crates/emmylua_code_analysis/src/compilation/test/generic_test.rs index dd47e750..64f30485 100644 --- a/crates/emmylua_code_analysis/src/compilation/test/generic_test.rs +++ b/crates/emmylua_code_analysis/src/compilation/test/generic_test.rs @@ -120,4 +120,42 @@ mod test { let expected = ws.ty("string"); assert_eq!(a_ty, expected); } + + #[test] + fn test_local_generics_in_global_scope() { + let mut ws = VirtualWorkspace::new(); + ws.def( + r#" + --- @generic T + --- @param x T + function foo(x) + a = x + end + "#, + ); + let a_ty = ws.expr_ty("a"); + assert_eq!(a_ty, ws.ty("unknown")); + } + + // Currently fails: + /* + #[test] + fn test_local_generics_in_global_scope_member() { + let mut ws = VirtualWorkspace::new(); + ws.def( + r#" + t = {} + + --- @generic T + --- @param x T + function foo(x) + t.a = x + end + local b = t.a + "#, + ); + let a_ty = ws.expr_ty("t.a"); + assert_eq!(a_ty, LuaType::Unknown); + } + */ } diff --git a/crates/emmylua_code_analysis/src/semantic/infer/infer_name.rs b/crates/emmylua_code_analysis/src/semantic/infer/infer_name.rs index 7eb39ea5..8bc056f7 100644 --- a/crates/emmylua_code_analysis/src/semantic/infer/infer_name.rs +++ b/crates/emmylua_code_analysis/src/semantic/infer/infer_name.rs @@ -344,9 +344,17 @@ pub fn infer_global_type(db: &DbIndex, name: &str) -> InferResult { .ok_or(InferFailReason::None)?; if decl_ids.len() == 1 { let id = decl_ids[0]; - return match db.get_type_index().get_type_cache(&id.into()) { - Some(type_cache) => Ok(type_cache.as_type().clone()), - None => Err(InferFailReason::UnResolveDeclType(id)), + let typ = match db.get_type_index().get_type_cache(&id.into()) { + Some(type_cache) => type_cache.as_type().clone(), + None => return Err(InferFailReason::UnResolveDeclType(id)), + }; + return if typ.contain_tpl() { + // This decl is located in a generic function, + // and is type contains references to generic variables + // of this function. + Ok(LuaType::Unknown) + } else { + Ok(typ) }; } @@ -365,6 +373,14 @@ pub fn infer_global_type(db: &DbIndex, name: &str) -> InferResult { match decl_type_cache { Some(type_cache) => { let typ = type_cache.as_type(); + + if typ.contain_tpl() { + // This decl is located in a generic function, + // and is type contains references to generic variables + // of this function. + continue; + } + if typ.is_def() || typ.is_ref() || typ.is_function() { return Ok(typ.clone()); }