aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/diagnostics/expr.rs')
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs119
1 files changed, 17 insertions, 102 deletions
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index b321004ac..c6015d236 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -4,7 +4,9 @@
4 4
5use std::{cell::RefCell, sync::Arc}; 5use std::{cell::RefCell, sync::Arc};
6 6
7use hir_def::{expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId}; 7use hir_def::{
8 expr::Statement, path::path, resolver::HasResolver, AssocItemId, DefWithBodyId, HasModule,
9};
8use hir_expand::name; 10use hir_expand::name;
9use rustc_hash::FxHashSet; 11use rustc_hash::FxHashSet;
10use syntax::{ast, AstPtr}; 12use syntax::{ast, AstPtr};
@@ -12,7 +14,10 @@ use syntax::{ast, AstPtr};
12use crate::{ 14use crate::{
13 db::HirDatabase, 15 db::HirDatabase,
14 diagnostics::{ 16 diagnostics::{
15 match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, 17 match_check::{
18 self,
19 usefulness::{compute_match_usefulness, expand_pattern, MatchCheckCtx, PatternArena},
20 },
16 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, 21 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr,
17 MissingPatFields, RemoveThisSemicolon, 22 MissingPatFields, RemoveThisSemicolon,
18 }, 23 },
@@ -26,13 +31,7 @@ pub(crate) use hir_def::{
26 LocalFieldId, VariantId, 31 LocalFieldId, VariantId,
27}; 32};
28 33
29use super::{ 34use super::ReplaceFilterMapNextWithFindMap;
30 pattern::{
31 self,
32 usefulness::{expand_pattern, PatternArena},
33 },
34 ReplaceFilterMapNextWithFindMap,
35};
36 35
37pub(super) struct ExprValidator<'a, 'b: 'a> { 36pub(super) struct ExprValidator<'a, 'b: 'a> {
38 owner: DefWithBodyId, 37 owner: DefWithBodyId,
@@ -68,7 +67,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
68 67
69 match expr { 68 match expr {
70 Expr::Match { expr, arms } => { 69 Expr::Match { expr, arms } => {
71 self.validate_match2(id, *expr, arms, db, self.infer.clone()); 70 self.validate_match(id, *expr, arms, db, self.infer.clone());
72 } 71 }
73 Expr::Call { .. } | Expr::MethodCall { .. } => { 72 Expr::Call { .. } | Expr::MethodCall { .. } => {
74 self.validate_call(db, id, expr); 73 self.validate_call(db, id, expr);
@@ -283,7 +282,6 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
283 } 282 }
284 } 283 }
285 284
286 #[allow(dead_code)]
287 fn validate_match( 285 fn validate_match(
288 &mut self, 286 &mut self,
289 id: ExprId, 287 id: ExprId,
@@ -301,90 +299,6 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
301 &infer.type_of_expr[match_expr] 299 &infer.type_of_expr[match_expr]
302 }; 300 };
303 301
304 let cx = MatchCheckCtx { match_expr, body, infer: infer.clone(), db };
305 let pats = arms.iter().map(|arm| arm.pat);
306
307 let mut seen = Matrix::empty();
308 for pat in pats {
309 if let Some(pat_ty) = infer.type_of_pat.get(pat) {
310 // We only include patterns whose type matches the type
311 // of the match expression. If we had a InvalidMatchArmPattern
312 // diagnostic or similar we could raise that in an else
313 // block here.
314 //
315 // When comparing the types, we also have to consider that rustc
316 // will automatically de-reference the match expression type if
317 // necessary.
318 //
319 // FIXME we should use the type checker for this.
320 if (pat_ty == match_expr_ty
321 || match_expr_ty
322 .as_reference()
323 .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
324 .unwrap_or(false))
325 && types_of_subpatterns_do_match(pat, &cx.body, &infer)
326 {
327 // If we had a NotUsefulMatchArm diagnostic, we could
328 // check the usefulness of each pattern as we added it
329 // to the matrix here.
330 let v = PatStack::from_pattern(pat);
331 seen.push(&cx, v);
332 continue;
333 }
334 }
335
336 // If we can't resolve the type of a pattern, or the pattern type doesn't
337 // fit the match expression, we skip this diagnostic. Skipping the entire
338 // diagnostic rather than just not including this match arm is preferred
339 // to avoid the chance of false positives.
340 return;
341 }
342
343 match is_useful(&cx, &seen, &PatStack::from_wild()) {
344 Ok(Usefulness::Useful) => (),
345 // if a wildcard pattern is not useful, then all patterns are covered
346 Ok(Usefulness::NotUseful) => return,
347 // this path is for unimplemented checks, so we err on the side of not
348 // reporting any errors
349 _ => return,
350 }
351
352 if let Ok(source_ptr) = source_map.expr_syntax(id) {
353 let root = source_ptr.file_syntax(db.upcast());
354 if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) {
355 if let (Some(match_expr), Some(arms)) =
356 (match_expr.expr(), match_expr.match_arm_list())
357 {
358 self.sink.push(MissingMatchArms {
359 file: source_ptr.file_id,
360 match_expr: AstPtr::new(&match_expr),
361 arms: AstPtr::new(&arms),
362 })
363 }
364 }
365 }
366 }
367
368 fn validate_match2(
369 &mut self,
370 id: ExprId,
371 match_expr: ExprId,
372 arms: &[MatchArm],
373 db: &dyn HirDatabase,
374 infer: Arc<InferenceResult>,
375 ) {
376 use crate::diagnostics::pattern::usefulness;
377 use hir_def::HasModule;
378
379 let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) =
380 db.body_with_source_map(self.owner);
381
382 let match_expr_ty = if infer.type_of_expr[match_expr].is_unknown() {
383 return;
384 } else {
385 &infer.type_of_expr[match_expr]
386 };
387
388 let pattern_arena = RefCell::new(PatternArena::new()); 302 let pattern_arena = RefCell::new(PatternArena::new());
389 303
390 let mut m_arms = Vec::new(); 304 let mut m_arms = Vec::new();
@@ -401,16 +315,17 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
401 // necessary. 315 // necessary.
402 // 316 //
403 // FIXME we should use the type checker for this. 317 // FIXME we should use the type checker for this.
404 if pat_ty == match_expr_ty 318 if (pat_ty == match_expr_ty
405 || match_expr_ty 319 || match_expr_ty
406 .as_reference() 320 .as_reference()
407 .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) 321 .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
408 .unwrap_or(false) 322 .unwrap_or(false))
323 && types_of_subpatterns_do_match(arm.pat, &body, &infer)
409 { 324 {
410 // If we had a NotUsefulMatchArm diagnostic, we could 325 // If we had a NotUsefulMatchArm diagnostic, we could
411 // check the usefulness of each pattern as we added it 326 // check the usefulness of each pattern as we added it
412 // to the matrix here. 327 // to the matrix here.
413 let m_arm = usefulness::MatchArm { 328 let m_arm = match_check::MatchArm {
414 pat: self.lower_pattern( 329 pat: self.lower_pattern(
415 arm.pat, 330 arm.pat,
416 &mut pattern_arena.borrow_mut(), 331 &mut pattern_arena.borrow_mut(),
@@ -434,14 +349,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
434 return; 349 return;
435 } 350 }
436 351
437 let cx = usefulness::MatchCheckCtx { 352 let cx = MatchCheckCtx {
438 module: self.owner.module(db.upcast()), 353 module: self.owner.module(db.upcast()),
439 match_expr, 354 match_expr,
440 infer: &infer, 355 infer: &infer,
441 db, 356 db,
442 pattern_arena: &pattern_arena, 357 pattern_arena: &pattern_arena,
443 }; 358 };
444 let report = usefulness::compute_match_usefulness(&cx, &m_arms); 359 let report = compute_match_usefulness(&cx, &m_arms);
445 360
446 // FIXME Report unreacheble arms 361 // FIXME Report unreacheble arms
447 // https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200-L201 362 // https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200-L201
@@ -473,8 +388,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
473 db: &dyn HirDatabase, 388 db: &dyn HirDatabase,
474 body: &Body, 389 body: &Body,
475 have_errors: &mut bool, 390 have_errors: &mut bool,
476 ) -> pattern::PatId { 391 ) -> match_check::PatId {
477 let mut patcx = pattern::PatCtxt::new(db, &self.infer, body); 392 let mut patcx = match_check::PatCtxt::new(db, &self.infer, body);
478 let pattern = patcx.lower_pattern(pat); 393 let pattern = patcx.lower_pattern(pat);
479 let pattern = pattern_arena.alloc(expand_pattern(pattern)); 394 let pattern = pattern_arena.alloc(expand_pattern(pattern));
480 if !patcx.errors.is_empty() { 395 if !patcx.errors.is_empty() {