Skip to content

Commit 8511576

Browse files
committed
Some later infer logical
1 parent cb79355 commit 8511576

6 files changed

Lines changed: 151 additions & 63 deletions

File tree

crates/emmylua_code_analysis/src/db_index/type/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub use type_decl::{
1515
};
1616
pub use type_ops::TypeOps;
1717
pub use type_owner::{LuaTypeCache, LuaTypeOwner};
18+
pub use type_visit_trait::TypeVisitTrait;
1819
pub use types::*;
1920

2021
#[derive(Debug)]

crates/emmylua_code_analysis/src/db_index/type/types.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -680,18 +680,6 @@ impl LuaFunctionType {
680680
false
681681
}
682682
}
683-
684-
pub fn collect_generic_tpls(&self, tpls: &mut HashSet<GenericTplId>) {
685-
self.visit_type(&mut |t| match t {
686-
LuaType::TplRef(generic_tpl) | LuaType::ConstTplRef(generic_tpl) => {
687-
tpls.insert(generic_tpl.get_tpl_id());
688-
}
689-
LuaType::StrTplRef(str_tpl) => {
690-
tpls.insert(str_tpl.get_tpl_id());
691-
}
692-
_ => {}
693-
});
694-
}
695683
}
696684

697685
impl From<LuaFunctionType> for LuaType {

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

Lines changed: 104 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,57 @@ use emmylua_parser::{LuaAstNode, LuaCallExpr, LuaExpr};
55
use crate::{
66
db_index::{DbIndex, LuaType},
77
semantic::{
8-
generic::tpl_context::TplContext, infer::InferFailReason, infer_expr, LuaInferCache,
8+
generic::{
9+
tpl_context::TplContext,
10+
tpl_pattern::{
11+
multi_param_tpl_pattern_match_multi_return, tpl_pattern_match,
12+
variadic_tpl_pattern_match,
13+
},
14+
},
15+
infer::InferFailReason,
16+
infer_expr, LuaInferCache,
917
},
10-
LuaFunctionType,
18+
LuaFunctionType, TypeVisitTrait,
1119
};
1220

13-
use super::{
14-
instantiate_type_generic::instantiate_doc_function, tpl_pattern::tpl_pattern_match_args,
15-
TypeSubstitutor,
16-
};
21+
use super::{instantiate_type_generic::instantiate_doc_function, TypeSubstitutor};
1722

1823
pub fn instantiate_func_generic(
1924
db: &DbIndex,
2025
cache: &mut LuaInferCache,
2126
func: &LuaFunctionType,
2227
call_expr: LuaCallExpr,
2328
) -> Result<LuaFunctionType, InferFailReason> {
29+
let mut generic_tpls = HashSet::new();
30+
func.visit_type(&mut |t| match t {
31+
LuaType::TplRef(generic_tpl) | LuaType::ConstTplRef(generic_tpl) => {
32+
let tpl_id = generic_tpl.get_tpl_id();
33+
if tpl_id.is_func() {
34+
generic_tpls.insert(tpl_id);
35+
}
36+
}
37+
LuaType::StrTplRef(str_tpl) => {
38+
generic_tpls.insert(str_tpl.get_tpl_id());
39+
}
40+
_ => {}
41+
});
42+
if generic_tpls.is_empty() {
43+
return Ok(func.clone());
44+
}
45+
2446
let origin_params = func.get_params();
25-
let func_param_types: Vec<_> = origin_params
47+
let mut func_param_types: Vec<_> = origin_params
2648
.iter()
2749
.map(|(_, t)| t.clone().unwrap_or(LuaType::Unknown))
2850
.collect();
29-
let func_return_type = func.get_ret();
3051

31-
let mut generic_tpls = HashSet::new();
32-
func.collect_generic_tpls(&mut generic_tpls);
33-
34-
let mut arg_types = collect_arg_types(db, cache, &call_expr)?;
52+
let arg_exprs = call_expr
53+
.get_args_list()
54+
.ok_or(InferFailReason::None)?
55+
.get_args()
56+
.collect::<Vec<_>>();
3557
let mut substitutor = TypeSubstitutor::new();
58+
substitutor.add_need_infer_tpls(generic_tpls);
3659
let mut context = TplContext {
3760
db,
3861
cache,
@@ -44,17 +67,81 @@ pub fn instantiate_func_generic(
4467
let colon_define = func.is_colon_define();
4568
match (colon_define, colon_call) {
4669
(true, false) => {
47-
if !arg_types.is_empty() {
48-
arg_types.remove(0);
49-
}
70+
func_param_types.insert(0, LuaType::Any);
5071
}
5172
(false, true) => {
52-
arg_types.insert(0, LuaType::Any);
73+
if !func_param_types.is_empty() {
74+
func_param_types.remove(0);
75+
}
5376
}
5477
_ => {}
5578
}
5679

57-
tpl_pattern_match_args(&mut context, &func_param_types, &arg_types)?;
80+
let mut unresolve_tpls = vec![];
81+
for i in 0..func_param_types.len() {
82+
if i >= arg_exprs.len() {
83+
break;
84+
}
85+
86+
if context.substitutor.is_infer_all_tpl() {
87+
break;
88+
}
89+
90+
let func_param_type = &func_param_types[i];
91+
let call_arg_expr = &arg_exprs[i];
92+
if !func_param_type.contain_tpl() {
93+
continue;
94+
}
95+
96+
if !func_param_type.is_variadic() {
97+
if let LuaExpr::ClosureExpr(_) = call_arg_expr {
98+
// If the argument is a closure, we cannot infer the type from it.
99+
// We will handle this case later.
100+
unresolve_tpls.push((func_param_type.clone(), call_arg_expr.clone()));
101+
continue;
102+
}
103+
}
104+
105+
let arg_type = infer_expr(db, context.cache, call_arg_expr.clone())?;
106+
107+
match (func_param_type, &arg_type) {
108+
(LuaType::Variadic(variadic), _) => {
109+
let mut arg_types = vec![];
110+
for arg_expr in &arg_exprs[i..] {
111+
let arg_type = infer_expr(db, context.cache, arg_expr.clone())?;
112+
arg_types.push(arg_type);
113+
}
114+
115+
variadic_tpl_pattern_match(&mut context, variadic, &arg_types)?;
116+
break;
117+
}
118+
(_, LuaType::Variadic(variadic)) => {
119+
multi_param_tpl_pattern_match_multi_return(
120+
&mut context,
121+
&func_param_types[i..],
122+
variadic,
123+
)?;
124+
break;
125+
}
126+
_ => {
127+
tpl_pattern_match(&mut context, func_param_type, &arg_type)?;
128+
}
129+
}
130+
}
131+
132+
if !context.substitutor.is_infer_all_tpl() {
133+
for (func_param_type, call_arg_expr) in unresolve_tpls {
134+
if let LuaExpr::ClosureExpr(_) = call_arg_expr {
135+
// If the argument is a closure, we cannot infer the type from it.
136+
// We will handle this case later.
137+
continue;
138+
}
139+
140+
let closure_type = infer_expr(db, context.cache, call_arg_expr)?;
141+
142+
tpl_pattern_match(&mut context, &func_param_type, &closure_type)?;
143+
}
144+
}
58145

59146
if func.contain_self() {
60147
infer_self_type(db, cache, &call_expr, &mut substitutor)?;
@@ -67,21 +154,6 @@ pub fn instantiate_func_generic(
67154
}
68155
}
69156

70-
fn collect_arg_types(
71-
db: &DbIndex,
72-
cache: &mut LuaInferCache,
73-
call_expr: &LuaCallExpr,
74-
) -> Result<Vec<LuaType>, InferFailReason> {
75-
let arg_list = call_expr.get_args_list().ok_or(InferFailReason::None)?;
76-
let mut arg_types = Vec::new();
77-
for arg in arg_list.get_args() {
78-
let arg_type = infer_expr(db, cache, arg.clone())?;
79-
arg_types.push(arg_type);
80-
}
81-
82-
Ok(arg_types)
83-
}
84-
85157
fn infer_self_type(
86158
db: &DbIndex,
87159
cache: &mut LuaInferCache,

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ fn instantiate_tuple(db: &DbIndex, tuple: &LuaTupleType, substitutor: &TypeSubst
6565
if let LuaType::TplRef(tpl) = base {
6666
if let Some(value) = substitutor.get(tpl.get_tpl_id()) {
6767
match value {
68+
SubstitutorValue::None => {}
6869
SubstitutorValue::MultiTypes(types) => {
6970
for typ in types {
7071
new_types.push(typ.clone());
@@ -124,6 +125,12 @@ pub fn instantiate_doc_function(
124125
new_params.push(param.clone());
125126
}
126127
}
128+
SubstitutorValue::MultiTypes(types) => {
129+
for (i, typ) in types.iter().enumerate() {
130+
let param_name = format!("param{}", i);
131+
new_params.push((param_name, Some(typ.clone())));
132+
}
133+
}
127134
_ => {
128135
new_params.push((
129136
"...".to_string(),
@@ -255,6 +262,7 @@ fn instantiate_table_generic(
255262
fn instantiate_tpl_ref(_: &DbIndex, tpl: &GenericTpl, substitutor: &TypeSubstitutor) -> LuaType {
256263
if let Some(value) = substitutor.get(tpl.get_tpl_id()) {
257264
match value {
265+
SubstitutorValue::None => {}
258266
SubstitutorValue::Type(ty) => return ty.clone(),
259267
SubstitutorValue::MultiTypes(types) => {
260268
return types.first().unwrap_or(&LuaType::Unknown).clone();
@@ -313,6 +321,7 @@ fn instantiate_variadic_type(
313321
if let LuaType::TplRef(tpl) = base {
314322
if let Some(value) = substitutor.get(tpl.get_tpl_id()) {
315323
match value {
324+
SubstitutorValue::None => {}
316325
SubstitutorValue::Type(ty) => return ty.clone(),
317326
SubstitutorValue::MultiTypes(types) => {
318327
return LuaType::Variadic(VariadicType::Multi(types.clone()).into())

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

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub fn tpl_pattern_match_args(
3333

3434
match (func_param_type, call_arg_type) {
3535
(LuaType::Variadic(variadic), _) => {
36-
variadic_tpl_pattern_match(variadic, &call_arg_types[i..], context.substitutor)?;
36+
variadic_tpl_pattern_match(context, variadic, &call_arg_types[i..])?;
3737
break;
3838
}
3939
(_, LuaType::Variadic(variadic)) => {
@@ -53,7 +53,7 @@ pub fn tpl_pattern_match_args(
5353
Ok(())
5454
}
5555

56-
fn multi_param_tpl_pattern_match_multi_return(
56+
pub fn multi_param_tpl_pattern_match_multi_return(
5757
context: &mut TplContext,
5858
func_param_types: &[LuaType],
5959
multi_return: &VariadicType,
@@ -97,7 +97,7 @@ fn multi_param_tpl_pattern_match_multi_return(
9797
Ok(())
9898
}
9999

100-
fn tpl_pattern_match(
100+
pub fn tpl_pattern_match(
101101
context: &mut TplContext,
102102
pattern: &LuaType,
103103
target: &LuaType,
@@ -639,12 +639,12 @@ fn return_type_pattern_match_target_type(
639639
}
640640
},
641641
VariadicType::Multi(target_types) => {
642-
variadic_tpl_pattern_match(variadic_source, target_types, context.substitutor)?;
642+
variadic_tpl_pattern_match(context, variadic_source, target_types)?;
643643
}
644644
}
645645
}
646646
(LuaType::Variadic(variadic), _) => {
647-
variadic_tpl_pattern_match(variadic, &[target.clone()], context.substitutor)?;
647+
variadic_tpl_pattern_match(context, variadic, &[target.clone()])?;
648648
}
649649
(_, LuaType::Variadic(variadic)) => {
650650
multi_param_tpl_pattern_match_multi_return(context, &[source.clone()], variadic)?;
@@ -682,23 +682,27 @@ fn func_varargs_tpl_pattern_match(
682682
}
683683

684684
pub fn variadic_tpl_pattern_match(
685+
context: &mut TplContext,
685686
tpl: &VariadicType,
686687
target_rest_types: &[LuaType],
687-
substitutor: &mut TypeSubstitutor,
688688
) -> TplPatternMatchResult {
689689
match tpl {
690690
VariadicType::Base(base) => {
691691
if let LuaType::TplRef(tpl_ref) = base {
692692
let tpl_id = tpl_ref.get_tpl_id();
693693
match target_rest_types.len() {
694694
0 => {
695-
substitutor.insert_type(tpl_id, LuaType::Nil);
695+
context.substitutor.insert_type(tpl_id, LuaType::Nil);
696696
}
697697
1 => {
698-
substitutor.insert_type(tpl_id, target_rest_types[0].clone());
698+
context
699+
.substitutor
700+
.insert_type(tpl_id, target_rest_types[0].clone());
699701
}
700702
_ => {
701-
substitutor.insert_multi_types(tpl_id, target_rest_types.to_vec());
703+
context
704+
.substitutor
705+
.insert_multi_types(tpl_id, target_rest_types.to_vec());
702706
}
703707
}
704708
}
@@ -708,11 +712,7 @@ pub fn variadic_tpl_pattern_match(
708712
match ret_type {
709713
LuaType::Variadic(inner) => {
710714
if i < target_rest_types.len() {
711-
variadic_tpl_pattern_match(
712-
inner,
713-
&target_rest_types[i..],
714-
substitutor,
715-
)?;
715+
variadic_tpl_pattern_match(context, inner, &target_rest_types[i..])?;
716716
}
717717

718718
break;
@@ -721,7 +721,7 @@ pub fn variadic_tpl_pattern_match(
721721
let tpl_id = tpl_ref.get_tpl_id();
722722
match target_rest_types.get(i) {
723723
Some(t) => {
724-
substitutor.insert_type(tpl_id, t.clone());
724+
context.substitutor.insert_type(tpl_id, t.clone());
725725
}
726726
None => {
727727
break;
@@ -752,7 +752,7 @@ fn tuple_tpl_pattern_match(
752752

753753
if let LuaType::Variadic(inner) = tpl_type {
754754
let target_rest_types = &target_tuple_types[i..];
755-
variadic_tpl_pattern_match(inner, target_rest_types, context.substitutor)?;
755+
variadic_tpl_pattern_match(context, inner, target_rest_types)?;
756756
break;
757757
}
758758

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

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::HashMap;
1+
use std::collections::{HashMap, HashSet};
22

33
use crate::{GenericTplId, LuaType, LuaTypeDeclId};
44

@@ -42,6 +42,23 @@ impl TypeSubstitutor {
4242
}
4343
}
4444

45+
pub fn add_need_infer_tpls(&mut self, tpl_ids: HashSet<GenericTplId>) {
46+
for tpl_id in tpl_ids {
47+
if !self.tpl_replace_map.contains_key(&tpl_id) {
48+
self.tpl_replace_map.insert(tpl_id, SubstitutorValue::None);
49+
}
50+
}
51+
}
52+
53+
pub fn is_infer_all_tpl(&self) -> bool {
54+
for value in self.tpl_replace_map.values() {
55+
if let SubstitutorValue::None = value {
56+
return false;
57+
}
58+
}
59+
true
60+
}
61+
4562
pub fn insert_type(&mut self, tpl_id: GenericTplId, replace_type: LuaType) {
4663
if !self.can_insert_type(tpl_id) {
4764
return;
@@ -53,8 +70,8 @@ impl TypeSubstitutor {
5370

5471
fn can_insert_type(&self, tpl_id: GenericTplId) -> bool {
5572
if let Some(value) = self.tpl_replace_map.get(&tpl_id) {
56-
if let SubstitutorValue::Type(typ) = value {
57-
return typ.is_any();
73+
if let SubstitutorValue::None = value {
74+
return true;
5875
}
5976

6077
return false;
@@ -140,6 +157,7 @@ fn convert_type_def_to_ref(ty: &LuaType) -> LuaType {
140157

141158
#[derive(Debug, Clone)]
142159
pub enum SubstitutorValue {
160+
None,
143161
Type(LuaType),
144162
Params(Vec<(String, Option<LuaType>)>),
145163
MultiTypes(Vec<LuaType>),

0 commit comments

Comments
 (0)