diff options
author | Dawer <[email protected]> | 2021-05-10 09:22:13 +0100 |
---|---|---|
committer | Dawer <[email protected]> | 2021-05-31 20:03:47 +0100 |
commit | 49e016169fc8413e2734a655cbd55ebba2907b76 (patch) | |
tree | 7688ba28eea44454e4d541890e1d311a3a87fffb /crates/hir_ty/src/diagnostics/expr.rs | |
parent | 9b841a9a044d9d71cece62a3e44880325bc15f78 (diff) |
Check pattern types.
Diffstat (limited to 'crates/hir_ty/src/diagnostics/expr.rs')
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 77 |
1 files changed, 48 insertions, 29 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()); |