Skip to content

Commit d0437e2

Browse files
committed
design how to use flow
1 parent fcfa142 commit d0437e2

6 files changed

Lines changed: 333 additions & 43 deletions

File tree

crates/emmylua_code_analysis/src/db_index/flow/flow_tree.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::collections::HashMap;
22

33
use emmylua_parser::LuaSyntaxId;
4-
use smol_str::SmolStr;
54

65
use crate::{FlowId, FlowNode, LuaDeclId};
76

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ impl LuaReferenceIndex {
111111
.get_decl_references(decl_id)
112112
}
113113

114+
pub fn get_var_reference_decl(
115+
&self,
116+
file_id: &FileId,
117+
range: TextRange,
118+
) -> Option<LuaDeclId> {
119+
self.file_references
120+
.get(file_id)?
121+
.get_decl_id(&range)
122+
}
123+
114124
pub fn get_decl_references_map(
115125
&self,
116126
file_id: &FileId,
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use emmylua_parser::{BinaryOperator, LuaAstNode, LuaChunk, LuaDocTagCast, LuaExpr};
2+
3+
use crate::{
4+
semantic::infer::infer_name::narrow::{
5+
get_single_antecedent, get_type_at_flow, ResultTypeOrContinue,
6+
},
7+
DbIndex, FileId, FlowNode, FlowTree, InFiled, InferFailReason, LuaDeclId, LuaInferCache,
8+
LuaType, LuaTypeOwner, TypeOps,
9+
};
10+
11+
pub fn get_type_at_cast_flow(
12+
db: &DbIndex,
13+
tree: &FlowTree,
14+
cache: &mut LuaInferCache,
15+
root: &LuaChunk,
16+
decl_id: LuaDeclId,
17+
flow_node: &FlowNode,
18+
tag_cast: LuaDocTagCast,
19+
) -> Result<ResultTypeOrContinue, InferFailReason> {
20+
let key_expr = match tag_cast.get_key_expr() {
21+
Some(expr) => expr,
22+
None => return Ok(ResultTypeOrContinue::Continue),
23+
};
24+
25+
// todo support index_expr
26+
let LuaExpr::NameExpr(name_expr) = key_expr else {
27+
return Ok(ResultTypeOrContinue::Continue);
28+
};
29+
let file_id = cache.get_file_id();
30+
let decl_tree = match db.get_decl_index().get_decl_tree(&file_id) {
31+
Some(tree) => tree,
32+
None => return Ok(ResultTypeOrContinue::Continue),
33+
};
34+
let name_text = match name_expr.get_name_text() {
35+
Some(text) => text,
36+
None => return Ok(ResultTypeOrContinue::Continue),
37+
};
38+
39+
let ref_decl = match decl_tree.find_local_decl(&name_text, tag_cast.get_position()) {
40+
Some(decl_id) => decl_id,
41+
None => return Ok(ResultTypeOrContinue::Continue),
42+
};
43+
44+
if ref_decl.get_id() != decl_id {
45+
return Ok(ResultTypeOrContinue::Continue);
46+
}
47+
48+
let antecedent_flow_id = get_single_antecedent(tree, flow_node)?;
49+
let antecedent_type = get_type_at_flow(db, tree, cache, root, decl_id, antecedent_flow_id)?;
50+
let cast_result = cast_type(db, cache.get_file_id(), &tag_cast, antecedent_type)?;
51+
Ok(ResultTypeOrContinue::Result(cast_result))
52+
}
53+
54+
enum CastAction {
55+
Add,
56+
Remove,
57+
Force,
58+
}
59+
60+
fn cast_type(
61+
db: &DbIndex,
62+
file_id: FileId,
63+
tag_cast: &LuaDocTagCast,
64+
mut source_type: LuaType,
65+
) -> Result<LuaType, InferFailReason> {
66+
for cast_op_type in tag_cast.get_op_types() {
67+
let action = match cast_op_type.get_op() {
68+
Some(op) => {
69+
if op.get_op() == BinaryOperator::OpAdd {
70+
CastAction::Add
71+
} else {
72+
CastAction::Remove
73+
}
74+
}
75+
None => CastAction::Force,
76+
};
77+
if cast_op_type.is_nullable() {
78+
match action {
79+
CastAction::Add => {
80+
source_type = TypeOps::Union.apply(db, &source_type, &LuaType::Nil);
81+
}
82+
CastAction::Remove => {
83+
source_type = TypeOps::Remove.apply(db, &source_type, &LuaType::Nil);
84+
}
85+
_ => {}
86+
}
87+
} else if let Some(doc_type) = cast_op_type.get_type() {
88+
let type_owner = LuaTypeOwner::SyntaxId(InFiled {
89+
file_id,
90+
value: doc_type.get_syntax_id(),
91+
});
92+
let typ = match db.get_type_index().get_type_cache(&type_owner) {
93+
Some(type_cache) => type_cache.as_type().clone(),
94+
None => {
95+
continue;
96+
}
97+
};
98+
match action {
99+
CastAction::Add => {
100+
source_type = TypeOps::Union.apply(db, &source_type, &typ);
101+
}
102+
CastAction::Remove => {
103+
source_type = TypeOps::Remove.apply(db, &source_type, &typ);
104+
}
105+
CastAction::Force => {
106+
source_type = typ;
107+
}
108+
}
109+
}
110+
}
111+
112+
Ok(source_type)
113+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use emmylua_parser::{LuaChunk, LuaExpr};
2+
3+
use crate::{
4+
semantic::infer::infer_name::narrow::ResultTypeOrContinue, DbIndex, FlowNode, FlowTree,
5+
InferFailReason, LuaDeclId, LuaInferCache,
6+
};
7+
8+
pub fn get_type_at_condition_flow(
9+
db: &DbIndex,
10+
tree: &FlowTree,
11+
cache: &mut LuaInferCache,
12+
root: &LuaChunk,
13+
decl_id: LuaDeclId,
14+
flow_node: &FlowNode,
15+
condition: LuaExpr,
16+
) -> Result<ResultTypeOrContinue, InferFailReason> {
17+
Ok(ResultTypeOrContinue::Continue)
18+
}

0 commit comments

Comments
 (0)