aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src
diff options
context:
space:
mode:
authorDawer <[email protected]>2021-05-10 09:22:13 +0100
committerDawer <[email protected]>2021-05-31 20:03:47 +0100
commit49e016169fc8413e2734a655cbd55ebba2907b76 (patch)
tree7688ba28eea44454e4d541890e1d311a3a87fffb /crates/hir_ty/src
parent9b841a9a044d9d71cece62a3e44880325bc15f78 (diff)
Check pattern types.
Diffstat (limited to 'crates/hir_ty/src')
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs77
-rw-r--r--crates/hir_ty/src/diagnostics/pattern.rs36
-rw-r--r--crates/hir_ty/src/diagnostics/pattern/usefulness.rs2
3 files changed, 85 insertions, 30 deletions
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 929c4a9cc..e4e9ab5c0 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -379,32 +379,58 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
379 let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) = 379 let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) =
380 db.body_with_source_map(self.owner); 380 db.body_with_source_map(self.owner);
381 381
382 let _match_expr_ty = if infer.type_of_expr[match_expr].is_unknown() { 382 let match_expr_ty = if infer.type_of_expr[match_expr].is_unknown() {
383 return; 383 return;
384 } else { 384 } else {
385 &infer.type_of_expr[match_expr] 385 &infer.type_of_expr[match_expr]
386 }; 386 };
387 // eprintln!("ExprValidator::validate_match2({:?})", _match_expr_ty.kind(&Interner));
388 387
389 let pattern_arena = RefCell::new(PatternArena::new()); 388 let pattern_arena = RefCell::new(PatternArena::new());
390 389
391 let mut have_errors = false; 390 let mut m_arms = Vec::new();
392 let m_arms: Vec<_> = arms 391 let mut has_lowering_errors = false;
393 .iter() 392 for arm in arms {
394 .map(|arm| usefulness::MatchArm { 393 if let Some(pat_ty) = infer.type_of_pat.get(arm.pat) {
395 pat: self.lower_pattern( 394 // We only include patterns whose type matches the type
396 arm.pat, 395 // of the match expression. If we had a InvalidMatchArmPattern
397 &mut pattern_arena.borrow_mut(), 396 // diagnostic or similar we could raise that in an else
398 db, 397 // block here.
399 &body, 398 //
400 &mut have_errors, 399 // When comparing the types, we also have to consider that rustc
401 ), 400 // will automatically de-reference the match expression type if
402 has_guard: arm.guard.is_some(), 401 // necessary.
403 }) 402 //
404 .collect(); 403 // FIXME we should use the type checker for this.
405 404 if pat_ty == match_expr_ty
406 // Bail out early if lowering failed. 405 || match_expr_ty
407 if have_errors { 406 .as_reference()
407 .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
408 .unwrap_or(false)
409 {
410 // If we had a NotUsefulMatchArm diagnostic, we could
411 // check the usefulness of each pattern as we added it
412 // to the matrix here.
413 let m_arm = usefulness::MatchArm {
414 pat: self.lower_pattern(
415 arm.pat,
416 &mut pattern_arena.borrow_mut(),
417 db,
418 &body,
419 &mut has_lowering_errors,
420 ),
421 has_guard: arm.guard.is_some(),
422 };
423 m_arms.push(m_arm);
424 if !has_lowering_errors {
425 continue;
426 }
427 }
428 }
429
430 // If we can't resolve the type of a pattern, or the pattern type doesn't
431 // fit the match expression, we skip this diagnostic. Skipping the entire
432 // diagnostic rather than just not including this match arm is preferred
433 // to avoid the chance of false positives.
408 return; 434 return;
409 } 435 }
410 436
@@ -418,18 +444,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
418 }; 444 };
419 let report = usefulness::compute_match_usefulness(&cx, &m_arms); 445 let report = usefulness::compute_match_usefulness(&cx, &m_arms);
420 446
421 // TODO Report unreacheble arms 447 // FIXME Report unreacheble arms
422 // let mut catchall = None; 448 // https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200-L201
423 // for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() {
424 // match is_useful{
425 // Unreachable => {
426 // }
427 // Reachable(_) => {}
428 // }
429 // }
430 449
431 let witnesses = report.non_exhaustiveness_witnesses; 450 let witnesses = report.non_exhaustiveness_witnesses;
432 eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses); 451 // eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses);
433 if !witnesses.is_empty() { 452 if !witnesses.is_empty() {
434 if let Ok(source_ptr) = source_map.expr_syntax(id) { 453 if let Ok(source_ptr) = source_map.expr_syntax(id) {
435 let root = source_ptr.file_syntax(db.upcast()); 454 let root = source_ptr.file_syntax(db.upcast());
diff --git a/crates/hir_ty/src/diagnostics/pattern.rs b/crates/hir_ty/src/diagnostics/pattern.rs
index d98fb0867..38e4b53b7 100644
--- a/crates/hir_ty/src/diagnostics/pattern.rs
+++ b/crates/hir_ty/src/diagnostics/pattern.rs
@@ -511,4 +511,40 @@ fn main() {
511"#, 511"#,
512 ); 512 );
513 } 513 }
514
515 /// These failing tests are narrowed down from "hir_ty::diagnostics::match_check::tests"
516 // TODO fix
517 mod failing {
518 use super::*;
519
520 #[test]
521 fn never() {
522 check_diagnostics(
523 r#"
524enum Never {}
525
526fn enum_ref(never: &Never) {
527 match never {}
528}
529"#,
530 );
531 }
532
533 #[test]
534 fn unknown_type() {
535 check_diagnostics(
536 r#"
537enum Option<T> { Some(T), None }
538
539fn main() {
540 // `Never` is deliberately not defined so that it's an uninferred type.
541 match Option::<Never>::None {
542 None => {}
543 Some(never) => {}
544 }
545}
546"#,
547 );
548 }
549 }
514} 550}
diff --git a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
index ef2be7530..01a7fb0d9 100644
--- a/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/pattern/usefulness.rs
@@ -28,7 +28,7 @@ pub(crate) struct MatchCheckCtx<'a> {
28 pub(crate) body: Arc<Body>, 28 pub(crate) body: Arc<Body>,
29 pub(crate) infer: &'a InferenceResult, 29 pub(crate) infer: &'a InferenceResult,
30 pub(crate) db: &'a dyn HirDatabase, 30 pub(crate) db: &'a dyn HirDatabase,
31 /// Patterns from self.body.pats plus generated by the check. 31 /// Lowered patterns from self.body.pats plus generated by the check.
32 pub(crate) pattern_arena: &'a RefCell<PatternArena>, 32 pub(crate) pattern_arena: &'a RefCell<PatternArena>,
33} 33}
34 34