Skip to content

Commit

Permalink
Move empty_match check after usefulness check
Browse files Browse the repository at this point in the history
  • Loading branch information
Nadrieril committed Dec 4, 2019
1 parent 3e6dc2b commit bfb556f
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 41 deletions.
2 changes: 2 additions & 0 deletions src/librustc_mir/hair/pattern/_match.rs
Expand Up @@ -1220,6 +1220,8 @@ impl<'tcx> Witness<'tcx> {
///
/// We make sure to omit constructors that are statically impossible. E.g., for
/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
/// `cx.is_uninhabited()`).
fn all_constructors<'a, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
pcx: PatCtxt<'tcx>,
Expand Down
78 changes: 37 additions & 41 deletions src/librustc_mir/hair/pattern/check_match.rs
Expand Up @@ -438,56 +438,52 @@ fn check_exhaustive<'p, 'tcx>(
// If the match has no arms, check whether the scrutinee is uninhabited.
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes, since an
// empty matrix can occur when there are arms, if those arms all have guards.
if is_empty_match {
let scrutinee_is_visibly_uninhabited = if cx.tcx.features().exhaustive_patterns {
let module = cx.tcx.hir().get_module_parent(hir_id);
cx.tcx.is_ty_uninhabited_from(module, scrut_ty)
} else {
match scrut_ty.kind {
ty::Never => true,
ty::Adt(def, _) if def.is_enum() => {
def.variants.is_empty() && !cx.is_foreign_non_exhaustive_enum(scrut_ty)
}
_ => false,
}
};
if scrutinee_is_visibly_uninhabited {
// If the type *is* uninhabited, it's vacuously exhaustive.
// This early return is only needed here because in the absence of the
// `exhaustive_patterns` feature, empty matches are not detected by `is_useful`
// to exhaustively match uninhabited types.
return;
} else {
// We know the type is inhabited, so this must be wrong
let non_empty_enum = match scrut_ty.kind {
ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
_ => false,
};

if non_empty_enum {
// Continue to the normal code path to display missing variants.
} else {
let mut err = create_e0004(
cx.tcx.sess,
sp,
format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
);
err.help(
"ensure that all possible cases are being handled, \
possibly by adding wildcards or more match arms",
);
adt_defined_here(cx, &mut err, scrut_ty, &[]);
err.emit();
return;
let scrutinee_is_visibly_uninhabited = if cx.tcx.features().exhaustive_patterns {
let module = cx.tcx.hir().get_module_parent(hir_id);
cx.tcx.is_ty_uninhabited_from(module, scrut_ty)
} else {
match scrut_ty.kind {
ty::Never => true,
ty::Adt(def, _) if def.is_enum() => {
def.variants.is_empty() && !cx.is_foreign_non_exhaustive_enum(scrut_ty)
}
_ => false,
}
};
if is_empty_match && scrutinee_is_visibly_uninhabited {
// If the type *is* uninhabited, it's vacuously exhaustive.
// This early return is only needed here because in the absence of the
// `exhaustive_patterns` feature, empty matches are not detected by `is_useful`
// to exhaustively match uninhabited types.
return;
}

let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {
Ok(_) => return,
Err(err) => err,
};

let non_empty_enum = match scrut_ty.kind {
ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
_ => false,
};
// In the case of an empty match, replace the '`_` not covered' diagnostic with something more
// informative.
if is_empty_match && !non_empty_enum {
let mut err = create_e0004(
cx.tcx.sess,
sp,
format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
);
err.help(
"ensure that all possible cases are being handled, \
possibly by adding wildcards or more match arms",
);
adt_defined_here(cx, &mut err, scrut_ty, &[]);
err.emit();
return;
}

let joined_patterns = joined_uncovered_patterns(&witnesses);
let mut err = create_e0004(
cx.tcx.sess,
Expand Down

0 comments on commit bfb556f

Please sign in to comment.