Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir/src/semantics.rs4
-rw-r--r--crates/hir/src/source_analyzer.rs29
-rw-r--r--crates/ide-assists/src/handlers/convert_match_to_let_else.rs2
-rw-r--r--crates/ide-assists/src/utils.rs10
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())
}