diff options
Diffstat (limited to 'crates/ra_hir_ty/src/expr.rs')
-rw-r--r-- | crates/ra_hir_ty/src/expr.rs | 53 |
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 | ||
15 | use crate::{ | 15 | use 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 | ||
22 | pub use hir_def::{ | 23 | pub 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, |