Skip to content

Commit b5208f9

Browse files
committed
fix #616
1 parent 6ad40ae commit b5208f9

6 files changed

Lines changed: 114 additions & 22 deletions

File tree

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,66 @@ mod test {
125125
));
126126
}
127127

128+
#[test]
129+
fn test_generic_type_extends() {
130+
let mut ws = VirtualWorkspace::new();
131+
let mut emmyrc = ws.get_emmyrc();
132+
emmyrc.runtime.class_default_call.force_non_colon = true;
133+
emmyrc.runtime.class_default_call.force_return_self = true;
134+
emmyrc.runtime.class_default_call.function_name = "__init".to_string();
135+
ws.update_emmyrc(emmyrc);
136+
ws.def(
137+
r#"
138+
---@class State
139+
---@field a string
140+
141+
---@class StateMachine<T: State>
142+
---@field aaa T
143+
---@field new fun(self: self): self
144+
StateMachine = {}
145+
146+
---@return self
147+
function StateMachine:abc()
148+
end
149+
150+
151+
---@return self
152+
function StateMachine:__init()
153+
end
154+
"#,
155+
);
156+
{
157+
ws.def(
158+
r#"
159+
A = StateMachine:new()
160+
"#,
161+
);
162+
let ty = ws.expr_ty("A");
163+
let expected = ws.ty("StateMachine<State>");
164+
assert_eq!(ty, expected);
165+
}
166+
{
167+
ws.def(
168+
r#"
169+
B = StateMachine:abc()
170+
"#,
171+
);
172+
let ty = ws.expr_ty("B");
173+
let expected = ws.ty("StateMachine<State>");
174+
assert_eq!(ty, expected);
175+
}
176+
{
177+
ws.def(
178+
r#"
179+
C = StateMachine:abc()
180+
"#,
181+
);
182+
let ty = ws.expr_ty("C");
183+
let expected = ws.ty("StateMachine<State>");
184+
assert_eq!(ty, expected);
185+
}
186+
}
187+
128188
#[test]
129189
fn test_type_return_usage() {
130190
let mut ws = VirtualWorkspace::new();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fn check_table_expr(
3333
let table_type = match semantic_model.infer_table_should_be(expr.clone())? {
3434
LuaType::Union(union) => {
3535
let mut set = HashSet::new();
36-
for ty in union.get_types() {
36+
for ty in union.into_vec().iter() {
3737
match ty {
3838
LuaType::Ref(_)
3939
| LuaType::Object(_)

crates/emmylua_code_analysis/src/semantic/generic/instantiate_func_generic.rs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use std::ops::Deref;
1+
use std::{ops::Deref, sync::Arc};
22

33
use emmylua_parser::{LuaAstNode, LuaCallExpr, LuaExpr};
4+
use internment::ArcIntern;
5+
use smol_str::SmolStr;
46

57
use crate::{
68
db_index::{DbIndex, LuaType},
79
semantic::{infer::InferFailReason, infer_expr, LuaInferCache},
8-
LuaFunctionType,
10+
GenericTpl, GenericTplId, LuaFunctionType, LuaGenericType,
911
};
1012

1113
use super::{
@@ -54,7 +56,9 @@ pub fn instantiate_func_generic(
5456
)?;
5557

5658
if func.contain_self() {
57-
infer_self_type(db, cache, &call_expr, &mut substitutor)?;
59+
if let Some(self_type) = infer_self_type(db, cache, &call_expr) {
60+
substitutor.add_self_type(self_type);
61+
}
5862
}
5963

6064
if let LuaType::DocFunction(f) = instantiate_doc_function(db, func, &substitutor) {
@@ -79,22 +83,46 @@ fn collect_arg_types(
7983
Ok(arg_types)
8084
}
8185

82-
fn infer_self_type(
86+
pub fn build_self_type(db: &DbIndex, self_type: &LuaType) -> LuaType {
87+
match self_type {
88+
LuaType::Def(id) | LuaType::Ref(id) => {
89+
if let Some(generic) = db.get_type_index().get_generic_params(id) {
90+
let mut params = Vec::new();
91+
for (i, ty) in generic.iter().enumerate() {
92+
if let Some(t) = &ty.1 {
93+
params.push(t.clone());
94+
} else {
95+
params.push(LuaType::TplRef(Arc::new(GenericTpl::new(
96+
GenericTplId::Type(i as u32),
97+
ArcIntern::new(SmolStr::from(ty.0.clone())),
98+
))));
99+
}
100+
}
101+
let generic = LuaGenericType::new(id.clone(), params);
102+
return LuaType::Generic(Arc::new(generic));
103+
}
104+
}
105+
_ => {}
106+
};
107+
self_type.clone()
108+
}
109+
110+
pub fn infer_self_type(
83111
db: &DbIndex,
84112
cache: &mut LuaInferCache,
85113
call_expr: &LuaCallExpr,
86-
substitutor: &mut TypeSubstitutor,
87-
) -> Result<(), InferFailReason> {
114+
) -> Option<LuaType> {
88115
let prefix_expr = call_expr.get_prefix_expr();
89116
if let Some(prefix_expr) = prefix_expr {
90117
if let LuaExpr::IndexExpr(index) = prefix_expr {
91118
let self_expr = index.get_prefix_expr();
92119
if let Some(self_expr) = self_expr {
93-
let self_type = infer_expr(db, cache, self_expr.into())?;
94-
substitutor.add_self_type(self_type);
120+
let self_type = infer_expr(db, cache, self_expr.into()).ok()?;
121+
let self_type = build_self_type(db, &self_type);
122+
return Some(self_type);
95123
}
96124
}
97125
}
98126

99-
Ok(())
127+
None
100128
}

crates/emmylua_code_analysis/src/semantic/generic/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ mod test;
55
mod tpl_pattern;
66
mod type_substitutor;
77

8+
pub use instantiate_func_generic::build_self_type;
9+
pub use instantiate_func_generic::infer_self_type;
810
pub use instantiate_func_generic::instantiate_func_generic;
911
pub use instantiate_type_generic::instantiate_doc_function;
1012
pub use instantiate_type_generic::instantiate_type_generic;

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

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ use super::{
1010
},
1111
InferFailReason, InferResult,
1212
};
13-
use crate::semantic::infer_expr;
1413
use crate::semantic::{
1514
generic::instantiate_doc_function, infer::narrow::get_type_at_call_expr_inline_cast,
1615
};
16+
use crate::{build_self_type, infer_self_type, semantic::infer_expr};
1717
use crate::{
1818
CacheEntry, DbIndex, InFiled, LuaFunctionType, LuaGenericType, LuaInstanceType,
1919
LuaOperatorMetaMethod, LuaOperatorOwner, LuaSignatureId, LuaType, LuaTypeDeclId, LuaUnionType,
@@ -265,7 +265,8 @@ fn infer_type_doc_function(
265265
LuaType::DocFunction(f) => {
266266
if f.contain_self() {
267267
let mut substitutor = TypeSubstitutor::new();
268-
substitutor.add_self_type(call_expr_type.clone());
268+
let self_type = build_self_type(db, call_expr_type);
269+
substitutor.add_self_type(self_type);
269270
if let LuaType::DocFunction(f) = instantiate_doc_function(db, &f, &substitutor)
270271
{
271272
overloads.push(f);
@@ -565,15 +566,8 @@ pub(crate) fn unwrapp_return_type(
565566
};
566567
}
567568
LuaType::SelfInfer => {
568-
let prefix_expr = call_expr.get_prefix_expr();
569-
if let Some(prefix_expr) = prefix_expr {
570-
if let LuaExpr::IndexExpr(index) = prefix_expr {
571-
let self_expr = index.get_prefix_expr();
572-
if let Some(self_expr) = self_expr {
573-
let self_type = infer_expr(db, cache, self_expr.into());
574-
return self_type;
575-
}
576-
}
569+
if let Some(self_type) = infer_self_type(db, cache, &call_expr) {
570+
return Ok(self_type);
577571
}
578572
}
579573
LuaType::TypeGuard(_) => return Ok(LuaType::Boolean),

crates/emmylua_code_analysis/src/test_lib/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::sync::Arc;
1+
use std::{ops::Deref, sync::Arc};
22

33
use emmylua_parser::{LuaAstNode, LuaAstToken, LuaLocalName};
44
use lsp_types::NumberOrString;
@@ -82,6 +82,14 @@ impl VirtualWorkspace {
8282
file_ids
8383
}
8484

85+
pub fn get_emmyrc(&self) -> Emmyrc {
86+
self.analysis.emmyrc.deref().clone()
87+
}
88+
89+
pub fn update_emmyrc(&mut self, emmyrc: Emmyrc) {
90+
self.analysis.update_config(Arc::new(emmyrc));
91+
}
92+
8593
pub fn get_node<Ast: LuaAstNode>(&self, file_id: FileId) -> Ast {
8694
let tree = self
8795
.analysis

0 commit comments

Comments
 (0)