Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/diagnostics/expr.rs')
-rw-r--r--crates/hir-ty/src/diagnostics/expr.rs83
1 files changed, 73 insertions, 10 deletions
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index eda8f2371c..7f8fb7f4b5 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -27,7 +27,7 @@ use crate::{
pub(crate) use hir_def::{
body::Body,
- hir::{Expr, ExprId, MatchArm, Pat, PatId},
+ hir::{Expr, ExprId, MatchArm, Pat, PatId, Statement},
LocalFieldId, VariantId,
};
@@ -44,6 +44,12 @@ pub enum BodyValidationDiagnostic {
match_expr: ExprId,
uncovered_patterns: String,
},
+ RemoveTrailingReturn {
+ return_expr: ExprId,
+ },
+ RemoveUnnecessaryElse {
+ if_expr: ExprId,
+ },
}
impl BodyValidationDiagnostic {
@@ -72,6 +78,10 @@ impl ExprValidator {
let body = db.body(self.owner);
let mut filter_map_next_checker = None;
+ if matches!(self.owner, DefWithBodyId::FunctionId(_)) {
+ self.check_for_trailing_return(body.body_expr, &body);
+ }
+
for (id, expr) in body.exprs.iter() {
if let Some((variant, missed_fields, true)) =
record_literal_missing_fields(db, &self.infer, id, expr)
@@ -90,9 +100,16 @@ impl ExprValidator {
Expr::Call { .. } | Expr::MethodCall { .. } => {
self.validate_call(db, id, expr, &mut filter_map_next_checker);
}
+ Expr::Closure { body: body_expr, .. } => {
+ self.check_for_trailing_return(*body_expr, &body);
+ }
+ Expr::If { .. } => {
+ self.check_for_unnecessary_else(id, expr, &body);
+ }
_ => {}
}
}
+
for (id, pat) in body.pats.iter() {
if let Some((variant, missed_fields, true)) =
record_pattern_missing_fields(db, &self.infer, id, pat)
@@ -153,14 +170,7 @@ impl ExprValidator {
}
let pattern_arena = Arena::new();
- let ty_arena = Arena::new();
- let cx = MatchCheckCtx::new(
- self.owner.module(db.upcast()),
- self.owner,
- db,
- &pattern_arena,
- &ty_arena,
- );
+ let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena);
let mut m_arms = Vec::with_capacity(arms.len());
let mut has_lowering_errors = false;
@@ -207,7 +217,7 @@ impl ExprValidator {
}
let report = match compute_match_usefulness(
- rustc_pattern_analysis::MatchCtxt { tycx: &cx },
+ &cx,
m_arms.as_slice(),
scrut_ty.clone(),
ValidityConstraint::ValidOnly,
@@ -244,6 +254,59 @@ impl ExprValidator {
}
pattern
}
+
+ fn check_for_trailing_return(&mut self, body_expr: ExprId, body: &Body) {
+ match &body.exprs[body_expr] {
+ Expr::Block { statements, tail, .. } => {
+ let last_stmt = tail.or_else(|| match statements.last()? {
+ Statement::Expr { expr, .. } => Some(*expr),
+ _ => None,
+ });
+ if let Some(last_stmt) = last_stmt {
+ self.check_for_trailing_return(last_stmt, body);
+ }
+ }
+ Expr::If { then_branch, else_branch, .. } => {
+ self.check_for_trailing_return(*then_branch, body);
+ if let Some(else_branch) = else_branch {
+ self.check_for_trailing_return(*else_branch, body);
+ }
+ }
+ Expr::Match { arms, .. } => {
+ for arm in arms.iter() {
+ let MatchArm { expr, .. } = arm;
+ self.check_for_trailing_return(*expr, body);
+ }
+ }
+ Expr::Return { .. } => {
+ self.diagnostics.push(BodyValidationDiagnostic::RemoveTrailingReturn {
+ return_expr: body_expr,
+ });
+ }
+ _ => (),
+ }
+ }
+
+ fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, body: &Body) {
+ if let Expr::If { condition: _, then_branch, else_branch } = expr {
+ if else_branch.is_none() {
+ return;
+ }
+ if let Expr::Block { statements, tail, .. } = &body.exprs[*then_branch] {
+ let last_then_expr = tail.or_else(|| match statements.last()? {
+ Statement::Expr { expr, .. } => Some(*expr),
+ _ => None,
+ });
+ if let Some(last_then_expr) = last_then_expr {
+ let last_then_expr_ty = &self.infer[last_then_expr];
+ if last_then_expr_ty.is_never() {
+ self.diagnostics
+ .push(BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr: id })
+ }
+ }
+ }
+ }
+ }
}
struct FilterMapNextChecker {