Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit ff70310

Browse files
committed
fix: only emit "unnecessary else" diagnostic for expr stmts
1 parent 1205853 commit ff70310

File tree

2 files changed

+49
-29
lines changed

2 files changed

+49
-29
lines changed

crates/hir-ty/src/diagnostics/expr.rs

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl ExprValidator {
109109
self.check_for_trailing_return(*body_expr, &body);
110110
}
111111
Expr::If { .. } => {
112-
self.check_for_unnecessary_else(id, expr, db);
112+
self.check_for_unnecessary_else(id, expr, &body, db);
113113
}
114114
Expr::Block { .. } => {
115115
self.validate_block(db, expr);
@@ -337,35 +337,17 @@ impl ExprValidator {
337337
}
338338
}
339339

340-
fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, db: &dyn HirDatabase) {
340+
fn check_for_unnecessary_else(
341+
&mut self,
342+
id: ExprId,
343+
expr: &Expr,
344+
body: &Body,
345+
db: &dyn HirDatabase,
346+
) {
341347
if let Expr::If { condition: _, then_branch, else_branch } = expr {
342348
if else_branch.is_none() {
343349
return;
344350
}
345-
let (body, source_map) = db.body_with_source_map(self.owner);
346-
let Ok(source_ptr) = source_map.expr_syntax(id) else {
347-
return;
348-
};
349-
let root = source_ptr.file_syntax(db.upcast());
350-
let ast::Expr::IfExpr(if_expr) = source_ptr.value.to_node(&root) else {
351-
return;
352-
};
353-
let mut top_if_expr = if_expr;
354-
loop {
355-
let parent = top_if_expr.syntax().parent();
356-
let has_parent_let_stmt =
357-
parent.as_ref().map_or(false, |node| ast::LetStmt::can_cast(node.kind()));
358-
if has_parent_let_stmt {
359-
// Bail if parent or direct ancestor is a let stmt.
360-
return;
361-
}
362-
let Some(parent_if_expr) = parent.and_then(ast::IfExpr::cast) else {
363-
// Parent is neither an if expr nor a let stmt.
364-
break;
365-
};
366-
// Check parent if expr.
367-
top_if_expr = parent_if_expr;
368-
}
369351
if let Expr::Block { statements, tail, .. } = &body.exprs[*then_branch] {
370352
let last_then_expr = tail.or_else(|| match statements.last()? {
371353
Statement::Expr { expr, .. } => Some(*expr),
@@ -374,6 +356,36 @@ impl ExprValidator {
374356
if let Some(last_then_expr) = last_then_expr {
375357
let last_then_expr_ty = &self.infer[last_then_expr];
376358
if last_then_expr_ty.is_never() {
359+
// Only look at sources if the then branch diverges and we have an else branch.
360+
let (_, source_map) = db.body_with_source_map(self.owner);
361+
let Ok(source_ptr) = source_map.expr_syntax(id) else {
362+
return;
363+
};
364+
let root = source_ptr.file_syntax(db.upcast());
365+
let ast::Expr::IfExpr(if_expr) = source_ptr.value.to_node(&root) else {
366+
return;
367+
};
368+
let mut top_if_expr = if_expr;
369+
loop {
370+
let parent = top_if_expr.syntax().parent();
371+
let has_parent_expr_stmt_or_stmt_list =
372+
parent.as_ref().map_or(false, |node| {
373+
ast::ExprStmt::can_cast(node.kind())
374+
| ast::StmtList::can_cast(node.kind())
375+
});
376+
if has_parent_expr_stmt_or_stmt_list {
377+
// Only emit diagnostic if parent or direct ancestor is either
378+
// an expr stmt or a stmt list.
379+
break;
380+
}
381+
let Some(parent_if_expr) = parent.and_then(ast::IfExpr::cast) else {
382+
// Bail if parent is neither an if expr, an expr stmt nor a stmt list.
383+
return;
384+
};
385+
// Check parent if expr.
386+
top_if_expr = parent_if_expr;
387+
}
388+
377389
self.diagnostics
378390
.push(BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr: id })
379391
}

crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -467,18 +467,18 @@ fn test() {
467467
}
468468

469469
#[test]
470-
fn no_diagnostic_if_tail_exists_in_else_branch() {
470+
fn no_diagnostic_if_not_expr_stmt() {
471471
check_diagnostics_with_needless_return_disabled(
472472
r#"
473-
fn test1(a: bool) {
473+
fn test1() {
474474
let _x = if a {
475475
return;
476476
} else {
477477
1
478478
};
479479
}
480480
481-
fn test2(a: bool, b: bool, c: bool) {
481+
fn test2() {
482482
let _x = if a {
483483
return;
484484
} else if b {
@@ -491,5 +491,13 @@ fn test2(a: bool, b: bool, c: bool) {
491491
}
492492
"#,
493493
);
494+
check_diagnostics_with_disabled(
495+
r#"
496+
fn test3() {
497+
foo(if a { return 1 } else { 0 })
498+
}
499+
"#,
500+
std::iter::once("E0308".to_owned()),
501+
);
494502
}
495503
}

0 commit comments

Comments
 (0)