From bfb556f97d47689ac110373de4986ce14fd52d30 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 4 Dec 2019 16:06:31 +0000 Subject: [PATCH] Move empty_match check after usefulness check --- src/librustc_mir/hair/pattern/_match.rs | 2 + src/librustc_mir/hair/pattern/check_match.rs | 78 ++++++++++---------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 0e8313a50bccf..4b451ad81c335 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -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>, diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 451e259ca7aed..d29169cb34108 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -438,49 +438,24 @@ 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) { @@ -488,6 +463,27 @@ fn check_exhaustive<'p, 'tcx>( 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,