Skip to content

Commit ff70310

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

2 files changed

Lines changed: 49 additions & 29 deletions

File tree

‎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-
fncheck_for_unnecessary_else(&mutself,id:ExprId,expr:&Expr,db:&dynHirDatabase){
340+
fncheck_for_unnecessary_else(
341+
&mutself,
342+
id:ExprId,
343+
expr:&Expr,
344+
body:&Body,
345+
db:&dynHirDatabase,
346+
){
341347
ifletExpr::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-
letOk(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-
letmut 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-
letSome(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
ifletExpr::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
ifletSome(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+
letOk(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+
letmut 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+
letSome(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-
fnno_diagnostic_if_tail_exists_in_else_branch(){
470+
fnno_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)