Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir/src/semantics.rs | 4 | ||||
| -rw-r--r-- | crates/hir/src/source_analyzer.rs | 29 | ||||
| -rw-r--r-- | crates/ide-assists/src/handlers/convert_match_to_let_else.rs | 2 | ||||
| -rw-r--r-- | crates/ide-assists/src/utils.rs | 10 |
4 files changed, 35 insertions, 10 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 0d6f9accf8..f633bb063f 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1772,6 +1772,10 @@ impl<'db> SemanticsImpl<'db> { }) } + pub fn expr_is_diverging(&self, expr: &ast::Expr) -> bool { + (|| self.analyze(expr.syntax())?.expr_is_diverging(self.db, expr))().unwrap_or(false) + } + pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo<'db>> { self.analyze(expr.syntax())? .type_of_expr(self.db, expr) diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 32e6acb6c5..1f9520d780 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -446,6 +446,35 @@ impl<'db> SourceAnalyzer<'db> { Some(self.ty(ty)) } + pub(crate) fn expr_is_diverging( + &self, + _db: &'db dyn HirDatabase, + expr: &ast::Expr, + ) -> Option<bool> { + let expr_id = self.expr_id(expr.clone())?; + let store = self.store()?; + let infer = self.infer()?; + Some(self.expr_id_is_diverging(store, infer, expr_id)) + } + + fn expr_id_is_diverging( + &self, + store: &ExpressionStore, + infer: &InferenceResult, + expr_id: ExprOrPatId, + ) -> bool { + // FIXME: This is an approximation, perhaps we need to store a set of diverging exprs in inference? + if infer.type_of_expr_or_pat(expr_id).is_some_and(|ty| ty.is_never()) { + true + } else if let ExprOrPatId::ExprId(expr_id) = expr_id + && let Expr::Block { tail: Some(tail), .. } = store[expr_id] + { + self.expr_id_is_diverging(store, infer, tail.into()) + } else { + false + } + } + pub(crate) fn type_of_expr( &self, _db: &'db dyn HirDatabase, diff --git a/crates/ide-assists/src/handlers/convert_match_to_let_else.rs b/crates/ide-assists/src/handlers/convert_match_to_let_else.rs index a93ab138e5..9dffdf3f36 100644 --- a/crates/ide-assists/src/handlers/convert_match_to_let_else.rs +++ b/crates/ide-assists/src/handlers/convert_match_to_let_else.rs @@ -93,7 +93,7 @@ fn find_arms( let mut extracting = None; let mut diverging = None; for arm in arms { - if ctx.sema.type_of_expr(&arm.expr()?)?.original().is_never() { + if ctx.sema.expr_is_diverging(&arm.expr()?) { diverging = Some(arm); } else { extracting = Some(arm); diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index 33e0f476da..1b6c9a579a 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -1182,13 +1182,5 @@ pub(crate) fn is_never_block( sema: &Semantics<'_, RootDatabase>, block_expr: &ast::BlockExpr, ) -> bool { - if let Some(tail_expr) = block_expr.tail_expr() { - sema.type_of_expr(&tail_expr).is_some_and(|ty| ty.original.is_never()) - } else if let Some(ast::Stmt::ExprStmt(expr_stmt)) = block_expr.statements().last() - && let Some(expr) = expr_stmt.expr() - { - sema.type_of_expr(&expr).is_some_and(|ty| ty.original.is_never()) - } else { - false - } + sema.expr_is_diverging(&block_expr.clone().into()) } |