Skip to content

Commit d217d86

Browse files
committed
fix #559
1 parent a0d420f commit d217d86

3 files changed

Lines changed: 62 additions & 19 deletions

File tree

  • crates/emmylua_code_analysis/src

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ fn get_real_type_with_depth<'a>(
5757
typ: &'a LuaType,
5858
depth: u32,
5959
) -> Option<&'a LuaType> {
60-
const MAX_RECURSION_DEPTH: u32 = 100;
60+
const MAX_RECURSION_DEPTH: u32 = 50;
6161

6262
if depth >= MAX_RECURSION_DEPTH {
6363
return Some(typ);

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

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use smol_str::SmolStr;
77
use crate::{
88
check_type_compact,
99
db_index::{DbIndex, LuaOperatorMetaMethod, LuaType},
10-
LuaInferCache, TypeOps,
10+
get_real_type, LuaInferCache, TypeOps,
1111
};
1212

1313
use super::{get_custom_type_operator, infer_expr, InferFailReason, InferResult};
@@ -21,18 +21,29 @@ pub fn infer_binary_expr(
2121
let (left, right) = expr.get_exprs().ok_or(InferFailReason::None)?;
2222
let left_type = infer_expr(db, cache, left.clone())?;
2323
let right_type = infer_expr(db, cache, right.clone())?;
24+
let real_left_type = get_real_type(db, &left_type);
25+
let real_right_type = get_real_type(db, &right_type);
26+
let left_type_ref = real_left_type.unwrap_or(&left_type);
27+
let right_type_ref = real_right_type.unwrap_or(&right_type);
2428

2529
if op == BinaryOperator::OpOr {
26-
if let Some(ty) = special_or_rule(db, &left_type, &right_type, left, right) {
30+
if let Some(ty) = special_or_rule(db, left_type_ref, right_type_ref, left, right) {
2731
return Ok(ty);
2832
}
2933
} else if !matches!(op, BinaryOperator::OpAnd | BinaryOperator::OpOr) {
30-
if let Some(ty) = infer_union_binary_expr(db, op, &left_type, &right_type) {
34+
if let Some(ty) = infer_union_binary_expr(db, op, left_type_ref, right_type_ref) {
3135
return Ok(ty);
3236
}
3337
}
3438

35-
infer_binary_expr_type(db, left_type, right_type, op)
39+
match (real_left_type.is_some(), real_right_type.is_some()) {
40+
(false, false) => infer_binary_expr_type(db, left_type, right_type, op),
41+
(true, false) => infer_binary_expr_type(db, left_type_ref.clone(), right_type, op),
42+
(false, true) => infer_binary_expr_type(db, left_type, right_type_ref.clone(), op),
43+
(true, true) => {
44+
infer_binary_expr_type(db, left_type_ref.clone(), right_type_ref.clone(), op)
45+
}
46+
}
3647
}
3748

3849
fn infer_union_binary_expr(
@@ -52,11 +63,14 @@ fn infer_union_binary_expr(
5263
let mut result = LuaType::Unknown;
5364
let types = u.get_types();
5465
for ty in types.iter() {
55-
if let Ok(ty) = if is_left_union {
66+
// 只在实际调用时才 clone,而不是预先 clone
67+
let ty_result = if is_left_union {
5668
infer_binary_expr_type(db, ty.clone(), other.clone(), op)
5769
} else {
5870
infer_binary_expr_type(db, other.clone(), ty.clone(), op)
59-
} {
71+
};
72+
73+
if let Ok(ty) = ty_result {
6074
result = TypeOps::Union.apply(db, &result, &ty);
6175
}
6276
}
@@ -101,22 +115,26 @@ fn infer_binary_custom_operator(
101115
right: &LuaType,
102116
op: LuaOperatorMetaMethod,
103117
) -> InferResult {
104-
let operators = get_custom_type_operator(db, left.clone(), op);
105-
if let Some(operators) = operators {
106-
for operator in operators {
107-
let operand = operator.get_operand(db);
108-
if check_type_compact(db, &operand, right).is_ok() {
109-
return operator.get_result(db);
118+
// 先检查 left 是否是自定义类型,避免不必要的 clone
119+
if left.is_custom_type() {
120+
if let Some(operators) = get_custom_type_operator(db, left.clone(), op) {
121+
for operator in operators {
122+
let operand = operator.get_operand(db);
123+
if check_type_compact(db, &operand, right).is_ok() {
124+
return operator.get_result(db);
125+
}
110126
}
111127
}
112128
}
113129

114-
let operators = get_custom_type_operator(db, right.clone(), op);
115-
if let Some(operators) = operators {
116-
for operator in operators {
117-
let operand = operator.get_operand(db);
118-
if check_type_compact(db, &operand, left).is_ok() {
119-
return operator.get_result(db);
130+
// 再检查 right 是否是自定义类型,只在需要时 clone
131+
if right.is_custom_type() {
132+
if let Some(operators) = get_custom_type_operator(db, right.clone(), op) {
133+
for operator in operators {
134+
let operand = operator.get_operand(db);
135+
if check_type_compact(db, &operand, left).is_ok() {
136+
return operator.get_result(db);
137+
}
120138
}
121139
}
122140
}

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,29 @@ mod test {
2424
let expected = ws.ty("AA");
2525
assert_eq!(ty, expected);
2626
}
27+
28+
#[test]
29+
fn test_issue_559() {
30+
let mut ws = VirtualWorkspace::new();
31+
32+
ws.def(
33+
r#"
34+
---@class Origin
35+
---@operator add(Origin):Origin
36+
37+
---@alias AliasType Origin
38+
39+
---@type AliasType
40+
local x1
41+
---@type AliasType
42+
local x2
43+
44+
A = x1 + x2
45+
"#,
46+
);
47+
48+
let ty = ws.expr_ty("A");
49+
let expected = ws.ty("Origin");
50+
assert_eq!(ty, expected);
51+
}
2752
}

0 commit comments

Comments
 (0)