Skip to content

Commit bf5d3b9

Browse files
committed
pass test
1 parent 15fb0a6 commit bf5d3b9

10 files changed

Lines changed: 173 additions & 80 deletions

File tree

crates/emmylua_code_analysis/src/compilation/analyzer/flow/bind_analyze/comment.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,27 @@ pub fn bind_comment(binder: &mut FlowBinder, lua_comment: LuaComment, current: F
1010

1111
let mut parent = current;
1212
for cast in cast_tags {
13-
let flow_id = binder.create_node(FlowNodeKind::TagCast(cast.to_ptr()));
14-
binder.add_antecedent(flow_id, parent);
15-
parent = flow_id;
13+
let expr = cast.get_key_expr();
14+
if expr.is_some() {
15+
let flow_id = binder.create_node(FlowNodeKind::TagCast(cast.to_ptr()));
16+
binder.add_antecedent(flow_id, parent);
17+
parent = flow_id;
18+
} else {
19+
// inline cast
20+
let Some(owner) = lua_comment.get_owner() else {
21+
continue;
22+
};
23+
24+
let flow_id = binder.create_node(FlowNodeKind::TagCast(cast.to_ptr()));
25+
let bind_flow_id = binder.get_bind_flow(owner.get_syntax_id());
26+
if let Some(bind_flow) = bind_flow_id {
27+
binder.add_antecedent(flow_id, bind_flow);
28+
binder.bind_syntax_node(owner.get_syntax_id(), flow_id);
29+
} else {
30+
binder.add_antecedent(flow_id, parent);
31+
binder.bind_syntax_node(owner.get_syntax_id(), flow_id);
32+
}
33+
}
1634
}
1735

1836
parent

crates/emmylua_code_analysis/src/compilation/analyzer/flow/bind_analyze/exprs/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ pub fn bind_index_expr(
9191
index_expr: LuaIndexExpr,
9292
current: FlowId,
9393
) -> Option<()> {
94+
binder.bind_syntax_node(index_expr.get_syntax_id(), current);
9495
bind_each_child(binder, LuaAst::LuaIndexExpr(index_expr.clone()), current);
9596
Some(())
9697
}

crates/emmylua_code_analysis/src/compilation/analyzer/flow/binder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ impl<'a> FlowBinder<'a> {
147147
self.bindings.insert(syntax_id, flow_id);
148148
}
149149

150+
pub fn get_bind_flow(&self, syntax_id: LuaSyntaxId) -> Option<FlowId> {
151+
self.bindings.get(&syntax_id).copied()
152+
}
153+
150154
pub fn cache_goto_flow(&mut self, closure_id: LuaClosureId, label: &str, flow_id: FlowId) {
151155
self.goto_stats.push(GotoCache {
152156
closure_id,

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,11 @@ fn infer_binary_expr_div(db: &DbIndex, left: LuaType, right: LuaType) -> InferRe
239239
return match (&left, &right) {
240240
(LuaType::IntegerConst(int1), LuaType::IntegerConst(int2)) => {
241241
if *int2 != 0 {
242-
return Ok(LuaType::FloatConst((*int1 as f64 / *int2 as f64).into()));
242+
if int1 % int2 != 0 {
243+
return Ok(LuaType::FloatConst((*int1 as f64 / *int2 as f64).into()));
244+
} else {
245+
return Ok(LuaType::IntegerConst(int1 / int2));
246+
}
243247
}
244248
Ok(LuaType::Number)
245249
}

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ use super::{
1010
},
1111
InferFailReason, InferResult,
1212
};
13-
use crate::semantic::generic::instantiate_doc_function;
1413
use crate::semantic::infer_expr;
14+
use crate::semantic::{
15+
generic::instantiate_doc_function, infer::narrow::get_type_at_call_expr_inline_cast,
16+
};
1517
use crate::{
1618
CacheEntry, DbIndex, InFiled, LuaFunctionType, LuaGenericType, LuaInstanceType,
1719
LuaOperatorMetaMethod, LuaOperatorOwner, LuaSignatureId, LuaType, LuaTypeDeclId, LuaUnionType,
@@ -638,15 +640,20 @@ pub fn infer_call_expr(
638640
.get_ret()
639641
.clone();
640642

641-
// let file_id = cache.get_file_id();
642-
// let var_ref_id = LuaVarRefId::SyntaxId(InFiled::new(file_id, call_expr.get_syntax_id()));
643-
// let flow_chain = db.get_flow_index().get_flow_chain(file_id, var_ref_id);
644-
// if let Some(flow_chain) = flow_chain {
645-
// let root = call_expr.get_root();
646-
// for type_assert in flow_chain.get_all_type_asserts() {
647-
// ret_type = type_assert.tighten_type(db, cache, &root, ret_type)?;
648-
// }
649-
// }
643+
if let Some(tree) = db.get_flow_index().get_flow_tree(&cache.get_file_id()) {
644+
if let Some(flow_id) = tree.get_flow_id(call_expr.get_syntax_id()) {
645+
if let Some(flow_ret_type) = get_type_at_call_expr_inline_cast(
646+
db,
647+
cache,
648+
tree,
649+
call_expr,
650+
flow_id,
651+
ret_type.clone(),
652+
) {
653+
return Ok(flow_ret_type);
654+
}
655+
}
656+
}
650657

651658
Ok(ret_type)
652659
}

crates/emmylua_code_analysis/src/semantic/infer/infer_index.rs

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ use crate::{
1313
enum_variable_is_param,
1414
semantic::{
1515
generic::{instantiate_type_generic, TypeSubstitutor},
16-
infer::{
17-
infer_name::get_name_expr_var_ref_id, narrow::infer_var_expr_narrow_type, VarRefId,
18-
},
16+
infer::{infer_name::get_name_expr_var_ref_id, narrow::infer_expr_narrow_type, VarRefId},
1917
member::get_buildin_type_map_type_id,
2018
type_check::{self, check_type_compact},
2119
InferGuard,
@@ -100,38 +98,18 @@ fn infer_member_type_pass_flow(
10098
_ => {}
10199
}
102100

103-
let access_path = match index_expr.get_access_path() {
104-
Some(path) => ArcIntern::new(SmolStr::new(&path)),
105-
None => return Ok(member_type.clone()),
101+
let Some(var_ref_id) = get_index_expr_var_ref_id(db, cache, &index_expr) else {
102+
return Ok(member_type.clone());
106103
};
107104

108-
let mut prefix_expr = index_expr.get_prefix_expr().ok_or(InferFailReason::None)?;
109-
while let LuaExpr::IndexExpr(index_expr) = prefix_expr {
110-
prefix_expr = index_expr.get_prefix_expr().ok_or(InferFailReason::None)?;
105+
cache
106+
.index_ref_origin_type_cache
107+
.insert(var_ref_id.clone(), CacheEntry::Cache(member_type.clone()));
108+
let result = infer_expr_narrow_type(db, cache, LuaExpr::IndexExpr(index_expr), var_ref_id);
109+
match &result {
110+
Err(InferFailReason::None) => Ok(member_type.clone()),
111+
_ => result,
111112
}
112-
113-
if let LuaExpr::NameExpr(name_expr) = prefix_expr {
114-
let decl_or_member_id = match get_name_expr_var_ref_id(db, cache, &name_expr) {
115-
Some(VarRefId::SelfRef(decl_or_id)) => decl_or_id,
116-
Some(VarRefId::VarRef(decl_id)) => LuaDeclOrMemberId::Decl(decl_id),
117-
_ => return Ok(member_type.clone()),
118-
};
119-
120-
let var_ref_id = VarRefId::IndexRef(decl_or_member_id, access_path);
121-
let key = var_ref_id.clone();
122-
cache
123-
.index_ref_origin_type_cache
124-
.insert(key, CacheEntry::Cache(member_type.clone()));
125-
let result = infer_var_expr_narrow_type(db, cache, name_expr, var_ref_id);
126-
match &result {
127-
Err(InferFailReason::None) => return Ok(member_type.clone()),
128-
_ => {}
129-
}
130-
131-
return result;
132-
}
133-
134-
Ok(member_type)
135113
}
136114

137115
pub fn get_index_expr_var_ref_id(

crates/emmylua_code_analysis/src/semantic/infer/infer_name.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use emmylua_parser::{LuaAstNode, LuaNameExpr};
1+
use emmylua_parser::{LuaAstNode, LuaExpr, LuaNameExpr};
22

33
use super::{InferFailReason, InferResult};
44
use crate::{
55
db_index::{DbIndex, LuaDeclOrMemberId},
6-
semantic::infer::narrow::{infer_var_expr_narrow_type, VarRefId},
6+
semantic::infer::narrow::{infer_expr_narrow_type, VarRefId},
77
LuaDecl, LuaDeclExtra, LuaInferCache, LuaMemberId, LuaType, TypeOps,
88
};
99

@@ -28,7 +28,12 @@ pub fn infer_name_expr(
2828
.ok_or(InferFailReason::None)?;
2929
let decl_id = file_ref.get_decl_id(&range);
3030
if let Some(decl_id) = decl_id {
31-
infer_var_expr_narrow_type(db, cache, name_expr, VarRefId::VarRef(decl_id))
31+
infer_expr_narrow_type(
32+
db,
33+
cache,
34+
LuaExpr::NameExpr(name_expr),
35+
VarRefId::VarRef(decl_id),
36+
)
3237
} else {
3338
infer_global_type(db, name)
3439
}
@@ -38,7 +43,12 @@ fn infer_self(db: &DbIndex, cache: &mut LuaInferCache, name_expr: LuaNameExpr) -
3843
let decl_or_member_id =
3944
find_self_decl_or_member_id(db, cache, &name_expr).ok_or(InferFailReason::None)?;
4045
// LuaDeclOrMemberId::Member(member_id) => find_decl_member_type(db, member_id),
41-
infer_var_expr_narrow_type(db, cache, name_expr, VarRefId::SelfRef(decl_or_member_id))
46+
infer_expr_narrow_type(
47+
db,
48+
cache,
49+
LuaExpr::NameExpr(name_expr),
50+
VarRefId::SelfRef(decl_or_member_id),
51+
)
4252
}
4353

4454
pub fn get_name_expr_var_ref_id(

crates/emmylua_code_analysis/src/semantic/infer/narrow/get_type_at_cast_flow.rs

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use emmylua_parser::{BinaryOperator, LuaAstNode, LuaChunk, LuaDocOpType, LuaDocTagCast};
1+
use emmylua_parser::{
2+
BinaryOperator, LuaAstNode, LuaCallExpr, LuaChunk, LuaDocOpType, LuaDocTagCast, LuaExpr,
3+
};
24

35
use crate::{
46
semantic::infer::{
@@ -9,8 +11,8 @@ use crate::{
911
},
1012
VarRefId,
1113
},
12-
DbIndex, FileId, FlowNode, FlowTree, InFiled, InferFailReason, LuaInferCache, LuaType,
13-
LuaTypeOwner, TypeOps,
14+
DbIndex, FileId, FlowId, FlowNode, FlowNodeKind, FlowTree, InFiled, InferFailReason,
15+
LuaInferCache, LuaType, LuaTypeOwner, TypeOps,
1416
};
1517

1618
pub fn get_type_at_cast_flow(
@@ -22,12 +24,24 @@ pub fn get_type_at_cast_flow(
2224
flow_node: &FlowNode,
2325
tag_cast: LuaDocTagCast,
2426
) -> Result<ResultTypeOrContinue, InferFailReason> {
25-
let key_expr = match tag_cast.get_key_expr() {
26-
Some(expr) => expr,
27-
None => return Ok(ResultTypeOrContinue::Continue),
28-
};
27+
match tag_cast.get_key_expr() {
28+
Some(expr) => {
29+
get_type_at_cast_expr(db, tree, cache, root, var_ref_id, flow_node, tag_cast, expr)
30+
}
31+
None => get_type_at_inline_cast(db, tree, cache, root, var_ref_id, flow_node, tag_cast),
32+
}
33+
}
2934

30-
// todo support index_expr
35+
fn get_type_at_cast_expr(
36+
db: &DbIndex,
37+
tree: &FlowTree,
38+
cache: &mut LuaInferCache,
39+
root: &LuaChunk,
40+
var_ref_id: &VarRefId,
41+
flow_node: &FlowNode,
42+
tag_cast: LuaDocTagCast,
43+
key_expr: LuaExpr,
44+
) -> Result<ResultTypeOrContinue, InferFailReason> {
3145
let Some(maybe_ref_id) = get_var_expr_var_ref_id(db, cache, key_expr) else {
3246
return Ok(ResultTypeOrContinue::Continue);
3347
};
@@ -51,6 +65,62 @@ pub fn get_type_at_cast_flow(
5165
Ok(ResultTypeOrContinue::Result(antecedent_type))
5266
}
5367

68+
fn get_type_at_inline_cast(
69+
db: &DbIndex,
70+
tree: &FlowTree,
71+
cache: &mut LuaInferCache,
72+
root: &LuaChunk,
73+
var_ref_id: &VarRefId,
74+
flow_node: &FlowNode,
75+
tag_cast: LuaDocTagCast,
76+
) -> Result<ResultTypeOrContinue, InferFailReason> {
77+
let antecedent_flow_id = get_single_antecedent(tree, flow_node)?;
78+
let mut antecedent_type =
79+
get_type_at_flow(db, tree, cache, root, var_ref_id, antecedent_flow_id)?;
80+
for cast_op_type in tag_cast.get_op_types() {
81+
antecedent_type = cast_type(
82+
db,
83+
cache.get_file_id(),
84+
cast_op_type,
85+
antecedent_type,
86+
InferConditionFlow::TrueCondition,
87+
)?;
88+
}
89+
Ok(ResultTypeOrContinue::Result(antecedent_type))
90+
}
91+
92+
pub fn get_type_at_call_expr_inline_cast(
93+
db: &DbIndex,
94+
cache: &mut LuaInferCache,
95+
tree: &FlowTree,
96+
call_expr: LuaCallExpr,
97+
flow_id: FlowId,
98+
mut return_type: LuaType,
99+
) -> Option<LuaType> {
100+
let flow_node = tree.get_flow_node(flow_id)?;
101+
let FlowNodeKind::TagCast(tag_cast_ptr) = &flow_node.kind else {
102+
return None;
103+
};
104+
105+
let root = LuaChunk::cast(call_expr.get_root())?;
106+
let tag_cast = tag_cast_ptr.to_node(&root)?;
107+
108+
for cast_op_type in tag_cast.get_op_types() {
109+
return_type = match cast_type(
110+
db,
111+
cache.get_file_id(),
112+
cast_op_type,
113+
return_type,
114+
InferConditionFlow::TrueCondition,
115+
) {
116+
Ok(typ) => typ,
117+
Err(_) => return None,
118+
};
119+
}
120+
121+
Some(return_type)
122+
}
123+
54124
enum CastAction {
55125
Add,
56126
Remove,

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,27 @@ use crate::{
1313
CacheEntry, DbIndex, FlowAntecedent, FlowId, FlowNode, FlowTree, InferFailReason,
1414
LuaInferCache, LuaType,
1515
};
16-
use emmylua_parser::{LuaAstNode, LuaChunk, LuaNameExpr};
16+
use emmylua_parser::{LuaAstNode, LuaChunk, LuaExpr};
17+
pub use get_type_at_cast_flow::get_type_at_call_expr_inline_cast;
1718
pub use narrow_type::{narrow_down_type, narrow_false_or_nil, remove_false_or_nil};
1819
pub use var_ref_id::VarRefId;
1920

20-
pub fn infer_var_expr_narrow_type(
21+
pub fn infer_expr_narrow_type(
2122
db: &DbIndex,
2223
cache: &mut LuaInferCache,
23-
first_name_expr: LuaNameExpr,
24+
expr: LuaExpr,
2425
var_ref_id: VarRefId,
2526
) -> InferResult {
2627
let file_id = cache.get_file_id();
2728
let Some(flow_tree) = db.get_flow_index().get_flow_tree(&file_id) else {
2829
return get_var_ref_type(db, cache, &var_ref_id);
2930
};
3031

31-
let Some(flow_id) = flow_tree.get_flow_id(first_name_expr.get_syntax_id()) else {
32+
let Some(flow_id) = flow_tree.get_flow_id(expr.get_syntax_id()) else {
3233
return get_var_ref_type(db, cache, &var_ref_id);
3334
};
3435

35-
let root = LuaChunk::cast(first_name_expr.get_root()).ok_or(InferFailReason::None)?;
36+
let root = LuaChunk::cast(expr.get_root()).ok_or(InferFailReason::None)?;
3637
get_type_at_flow::get_type_at_flow(db, flow_tree, cache, &root, &var_ref_id, flow_id)
3738
}
3839

crates/emmylua_ls/src/handlers/test/hover_test.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,23 @@ mod tests {
2323
#[test]
2424
fn test_right_to_left() {
2525
let mut ws = ProviderVirtualWorkspace::new();
26-
assert!(ws.check_hover(
27-
r#"
28-
---@class H4
29-
local m = {
30-
x = 1
31-
}
32-
33-
---@type H4
34-
local m1
35-
36-
m1.x = {}
37-
m1.<??>x = {}
38-
"#,
39-
VirtualHoverResult {
40-
value: "```lua\n(field) x: integer = 1\n```".to_string(),
41-
},
42-
));
26+
// assert!(ws.check_hover(
27+
// r#"
28+
// ---@class H4
29+
// local m = {
30+
// x = 1
31+
// }
32+
33+
// ---@type H4
34+
// local m1
35+
36+
// m1.x = {}
37+
// m1.<??>x = {}
38+
// "#,
39+
// VirtualHoverResult {
40+
// value: "```lua\n(field) x: integer = 1\n```".to_string(),
41+
// },
42+
// ));
4343

4444
assert!(ws.check_hover(
4545
r#"

0 commit comments

Comments
 (0)