mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 14:21:44 +00:00
Display witnesses of non-exhaustive match
Reporting format follows rustc and shows at most three witnesses.
This commit is contained in:
parent
ad6810e90b
commit
4ff9bedbed
6 changed files with 320 additions and 80 deletions
|
@ -4,9 +4,10 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
use hir_def::{path::path, resolver::HasResolver, AssocItemId, DefWithBodyId, HasModule};
|
||||
use hir_def::{path::path, resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule};
|
||||
use hir_expand::name;
|
||||
use itertools::Either;
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashSet;
|
||||
use typed_arena::Arena;
|
||||
|
||||
|
@ -17,7 +18,8 @@ use crate::{
|
|||
deconstruct_pat::DeconstructedPat,
|
||||
usefulness::{compute_match_usefulness, MatchCheckCtx},
|
||||
},
|
||||
InferenceResult, TyExt,
|
||||
display::HirDisplay,
|
||||
InferenceResult, Ty, TyExt,
|
||||
};
|
||||
|
||||
pub(crate) use hir_def::{
|
||||
|
@ -37,6 +39,7 @@ pub enum BodyValidationDiagnostic {
|
|||
},
|
||||
MissingMatchArms {
|
||||
match_expr: ExprId,
|
||||
uncovered_patterns: String,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -211,10 +214,11 @@ impl ExprValidator {
|
|||
// https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200
|
||||
|
||||
let witnesses = report.non_exhaustiveness_witnesses;
|
||||
// FIXME Report witnesses
|
||||
// eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses);
|
||||
if !witnesses.is_empty() {
|
||||
self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms { match_expr: id });
|
||||
self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms {
|
||||
match_expr: id,
|
||||
uncovered_patterns: missing_match_arms(&cx, match_expr_ty, witnesses, arms),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,3 +371,40 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
|
|||
walk(pat, body, infer, &mut has_type_mismatches);
|
||||
!has_type_mismatches
|
||||
}
|
||||
|
||||
fn missing_match_arms<'p>(
|
||||
cx: &MatchCheckCtx<'_, 'p>,
|
||||
scrut_ty: &Ty,
|
||||
witnesses: Vec<DeconstructedPat<'p>>,
|
||||
arms: &[MatchArm],
|
||||
) -> String {
|
||||
let non_empty_enum = match scrut_ty.as_adt() {
|
||||
Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(),
|
||||
_ => false,
|
||||
};
|
||||
if arms.is_empty() && !non_empty_enum {
|
||||
format!("type `{}` is non-empty", scrut_ty.display(cx.db))
|
||||
} else {
|
||||
const LIMIT: usize = 3;
|
||||
match &*witnesses {
|
||||
[witness] => format!("`{}` not covered", witness.to_pat(&cx).display(cx.db)),
|
||||
[head @ .., tail] if head.len() < LIMIT => {
|
||||
let head: Vec<_> = head.iter().map(|w| w.to_pat(cx)).collect();
|
||||
format!(
|
||||
"`{}` and `{}` not covered",
|
||||
head.iter().map(|p| p.display(cx.db)).join("`, `"),
|
||||
tail.to_pat(&cx).display(cx.db)
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let (head, tail) = witnesses.split_at(LIMIT);
|
||||
let head: Vec<_> = head.iter().map(|w| w.to_pat(cx)).collect();
|
||||
format!(
|
||||
"`{}` and {} more not covered",
|
||||
head.iter().map(|p| p.display(cx.db)).join("`, `"),
|
||||
tail.len()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue