aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/expr.rs')
-rw-r--r--crates/ra_hir_ty/src/expr.rs53
1 files changed, 51 insertions, 2 deletions
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index b7b476b4c..3caeeb394 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -14,9 +14,10 @@ use rustc_hash::FxHashSet;
14 14
15use crate::{ 15use crate::{
16 db::HirDatabase, 16 db::HirDatabase,
17 diagnostics::{MissingFields, MissingOkInTailExpr}, 17 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr},
18 utils::variant_data, 18 utils::variant_data,
19 ApplicationTy, InferenceResult, Ty, TypeCtor, 19 ApplicationTy, InferenceResult, Ty, TypeCtor,
20 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
20}; 21};
21 22
22pub use hir_def::{ 23pub use hir_def::{
@@ -52,15 +53,63 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
52 for e in body.exprs.iter() { 53 for e in body.exprs.iter() {
53 if let (id, Expr::RecordLit { path, fields, spread }) = e { 54 if let (id, Expr::RecordLit { path, fields, spread }) = e {
54 self.validate_record_literal(id, path, fields, *spread, db); 55 self.validate_record_literal(id, path, fields, *spread, db);
56 } else if let (id, Expr::Match { expr, arms }) = e {
57 self.validate_match(id, *expr, arms, db, self.infer.clone());
55 } 58 }
56 } 59 }
57 60
58 let body_expr = &body[body.body_expr]; 61 let body_expr = &body[body.body_expr];
59 if let Expr::Block { statements: _, tail: Some(t) } = body_expr { 62 if let Expr::Block { tail: Some(t), .. } = body_expr {
60 self.validate_results_in_tail_expr(body.body_expr, *t, db); 63 self.validate_results_in_tail_expr(body.body_expr, *t, db);
61 } 64 }
62 } 65 }
63 66
67 fn validate_match(
68 &mut self,
69 id: ExprId,
70 expr: ExprId,
71 arms: &[MatchArm],
72 db: &dyn HirDatabase,
73 infer: Arc<InferenceResult>,
74 ) {
75 let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) =
76 db.body_with_source_map(self.func.into());
77
78 let match_expr: &hir_def::expr::Expr = &body[expr];
79
80 let cx = MatchCheckCtx { body: body.clone(), match_expr, infer, db };
81 let pats = arms.iter().map(|arm| arm.pat);
82
83 let mut seen = Matrix::empty();
84 for pat in pats {
85 // If we had a NotUsefulMatchArm diagnostic, we could
86 // check the usefulness of each pattern as we added it
87 // to the matrix here.
88 let v = PatStack::from_pattern(pat);
89 seen.push(&cx, v);
90 }
91
92 match is_useful(&cx, &seen, &PatStack::from_wild()) {
93 Usefulness::Useful => (),
94 // if a wildcard pattern is not useful, then all patterns are covered
95 Usefulness::NotUseful => return,
96 }
97
98 if let Ok(source_ptr) = source_map.expr_syntax(id) {
99 if let Some(expr) = source_ptr.value.left() {
100 let root = source_ptr.file_syntax(db.upcast());
101 if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) {
102 if let Some(arms) = match_expr.match_arm_list() {
103 self.sink.push(MissingMatchArms {
104 file: source_ptr.file_id,
105 arms: AstPtr::new(&arms),
106 })
107 }
108 }
109 }
110 }
111 }
112
64 fn validate_record_literal( 113 fn validate_record_literal(
65 &mut self, 114 &mut self,
66 id: ExprId, 115 id: ExprId,