@@ -12,6 +12,7 @@ use hir_expand::name;
1212use itertools:: Itertools ;
1313use rustc_hash:: FxHashSet ;
1414use rustc_pattern_analysis:: usefulness:: { compute_match_usefulness, ValidityConstraint } ;
15+ use syntax:: { ast, AstNode } ;
1516use tracing:: debug;
1617use triomphe:: Arc ;
1718use typed_arena:: Arena ;
@@ -108,7 +109,7 @@ impl ExprValidator {
108109 self . check_for_trailing_return ( * body_expr, & body) ;
109110 }
110111 Expr :: If { .. } => {
111- self . check_for_unnecessary_else ( id, expr, & body ) ;
112+ self . check_for_unnecessary_else ( id, expr, db ) ;
112113 }
113114 Expr :: Block { .. } => {
114115 self . validate_block ( db, expr) ;
@@ -336,31 +337,34 @@ impl ExprValidator {
336337 }
337338 }
338339
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 ) {
340341 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 {
363347 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;
364368 }
365369 if let Expr :: Block { statements, tail, .. } = & body. exprs [ * then_branch] {
366370 let last_then_expr = tail. or_else ( || match statements. last ( ) ? {
0 commit comments