@@ -12,6 +12,7 @@ use hir_expand::name;
12
12
use itertools:: Itertools ;
13
13
use rustc_hash:: FxHashSet ;
14
14
use rustc_pattern_analysis:: usefulness:: { compute_match_usefulness, ValidityConstraint } ;
15
+ use syntax:: { ast, AstNode } ;
15
16
use tracing:: debug;
16
17
use triomphe:: Arc ;
17
18
use typed_arena:: Arena ;
@@ -108,7 +109,7 @@ impl ExprValidator {
108
109
self . check_for_trailing_return ( * body_expr, & body) ;
109
110
}
110
111
Expr :: If { .. } => {
111
- self . check_for_unnecessary_else ( id, expr, & body ) ;
112
+ self . check_for_unnecessary_else ( id, expr, db ) ;
112
113
}
113
114
Expr :: Block { .. } => {
114
115
self . validate_block ( db, expr) ;
@@ -336,31 +337,34 @@ impl ExprValidator {
336
337
}
337
338
}
338
339
339
- fn check_for_unnecessary_else ( & mut self , id : ExprId , expr : & Expr , body : & Body ) {
340
+ fn check_for_unnecessary_else ( & mut self , id : ExprId , expr : & Expr , db : & dyn HirDatabase ) {
340
341
if let Expr :: If { condition : _, then_branch, else_branch } = expr {
341
- if let Some ( else_branch) = else_branch {
342
- // If else branch has a tail, it is an "expression" that produces a value,
343
- // e.g. `let a = if { ... } else { ... };` and this `else` is not unnecessary
344
- let mut branch = * else_branch;
345
- loop {
346
- match body. exprs [ branch] {
347
- Expr :: Block { tail : Some ( _) , .. } => return ,
348
- Expr :: If { then_branch, else_branch, .. } => {
349
- if let Expr :: Block { tail : Some ( _) , .. } = body. exprs [ then_branch] {
350
- return ;
351
- }
352
- if let Some ( else_branch) = else_branch {
353
- // Continue checking for branches like `if { ... } else if { ... } else...`
354
- branch = else_branch;
355
- continue ;
356
- }
357
- }
358
- _ => break ,
359
- }
360
- break ;
361
- }
362
- } else {
342
+ if else_branch. is_none ( ) {
343
+ return ;
344
+ }
345
+ let ( body, source_map) = db. body_with_source_map ( self . owner ) ;
346
+ let Ok ( source_ptr) = source_map. expr_syntax ( id) else {
363
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;
364
368
}
365
369
if let Expr :: Block { statements, tail, .. } = & body. exprs [ * then_branch] {
366
370
let last_then_expr = tail. or_else ( || match statements. last ( ) ? {
0 commit comments