about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs27
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs160
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs151
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs134
4 files changed, 212 insertions, 260 deletions
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 88a5eae281b..f9a8795f5d6 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -16,7 +16,7 @@ use rustc_data_structures::{
 };
 use rustc_index::bit_set::BitSet;
 use rustc_middle::middle::region;
-use rustc_middle::mir::*;
+use rustc_middle::mir::{self, *};
 use rustc_middle::thir::{self, *};
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
 use rustc_span::symbol::Symbol;
@@ -1053,17 +1053,30 @@ struct Ascription<'tcx> {
 }
 
 #[derive(Debug, Clone)]
+enum TestCase<'pat, 'tcx> {
+    Irrefutable { binding: Option<Binding<'tcx>>, ascription: Option<Ascription<'tcx>> },
+    Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
+    Constant { value: mir::Const<'tcx> },
+    Range(&'pat PatRange<'tcx>),
+    Slice { len: usize, variable_length: bool },
+    Or,
+}
+
+#[derive(Debug, Clone)]
 pub(crate) struct MatchPair<'pat, 'tcx> {
-    // This place...
+    /// This place...
     place: PlaceBuilder<'tcx>,
 
-    // ... must match this pattern.
-    // Invariant: after creation and simplification in `Candidate::new()`, all match pairs must be
-    // simplified, i.e. require a test.
-    pattern: &'pat Pat<'tcx>,
+    /// ... must pass this test...
+    // Invariant: after creation and simplification in `Candidate::new()`, this must not be
+    // `Irrefutable`.
+    test_case: TestCase<'pat, 'tcx>,
 
-    /// Precomputed sub-match pairs of `pattern`.
+    /// ... and these subpairs must match.
     subpairs: Vec<Self>,
+
+    /// The pattern this was created from.
+    pattern: &'pat Pat<'tcx>,
 }
 
 /// See [`Test`] for more.
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 83922dce327..53a5056cc3f 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -13,11 +13,9 @@
 //! testing a value against a constant.
 
 use crate::build::expr::as_place::PlaceBuilder;
-use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
+use crate::build::matches::{Ascription, Binding, Candidate, MatchPair, TestCase};
 use crate::build::Builder;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::thir::{self, *};
-use rustc_middle::ty;
+use rustc_middle::thir::{Pat, PatKind};
 
 use std::mem;
 
@@ -62,13 +60,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let mut simplified_match_pairs = Vec::new();
         // Repeatedly simplify match pairs until we're left with only unsimplifiable ones.
         loop {
-            for match_pair in mem::take(match_pairs) {
-                if let Err(match_pair) = self.simplify_match_pair(
-                    match_pair,
-                    candidate_bindings,
-                    candidate_ascriptions,
-                    match_pairs,
-                ) {
+            for mut match_pair in mem::take(match_pairs) {
+                if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
+                    if let Some(binding) = binding {
+                        candidate_bindings.push(binding);
+                    }
+                    if let Some(ascription) = ascription {
+                        candidate_ascriptions.push(ascription);
+                    }
+                    // Simplifiable pattern; we replace it with its subpairs and simplify further.
+                    match_pairs.append(&mut match_pair.subpairs);
+                } else {
+                    // Unsimplifiable pattern; we recursively simplify its subpairs and don't
+                    // process it further.
+                    self.simplify_match_pairs(
+                        &mut match_pair.subpairs,
+                        candidate_bindings,
+                        candidate_ascriptions,
+                    );
                     simplified_match_pairs.push(match_pair);
                 }
             }
@@ -117,133 +126,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             })
             .collect()
     }
-
-    /// Tries to simplify `match_pair`, returning `Ok(())` if successful. If successful, new match
-    /// pairs and bindings will have been pushed into the respective `Vec`s. If no simplification is
-    /// possible, `Err` is returned.
-    fn simplify_match_pair<'pat>(
-        &mut self,
-        mut match_pair: MatchPair<'pat, 'tcx>,
-        bindings: &mut Vec<Binding<'tcx>>,
-        ascriptions: &mut Vec<Ascription<'tcx>>,
-        match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
-    ) -> Result<(), MatchPair<'pat, 'tcx>> {
-        match match_pair.pattern.kind {
-            PatKind::Leaf { .. }
-            | PatKind::Deref { .. }
-            | PatKind::Array { .. }
-            | PatKind::Never
-            | PatKind::Wild
-            | PatKind::Error(_) => {}
-
-            PatKind::AscribeUserType {
-                ascription: thir::Ascription { ref annotation, variance },
-                ..
-            } => {
-                // Apply the type ascription to the value at `match_pair.place`
-                if let Some(source) = match_pair.place.try_to_place(self) {
-                    ascriptions.push(Ascription {
-                        annotation: annotation.clone(),
-                        source,
-                        variance,
-                    });
-                }
-            }
-
-            PatKind::Binding {
-                name: _,
-                mutability: _,
-                mode,
-                var,
-                ty: _,
-                subpattern: _,
-                is_primary: _,
-            } => {
-                if let Some(source) = match_pair.place.try_to_place(self) {
-                    bindings.push(Binding {
-                        span: match_pair.pattern.span,
-                        source,
-                        var_id: var,
-                        binding_mode: mode,
-                    });
-                }
-            }
-
-            PatKind::InlineConstant { subpattern: ref pattern, def } => {
-                // Apply a type ascription for the inline constant to the value at `match_pair.place`
-                if let Some(source) = match_pair.place.try_to_place(self) {
-                    let span = match_pair.pattern.span;
-                    let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id());
-                    let args = ty::InlineConstArgs::new(
-                        self.tcx,
-                        ty::InlineConstArgsParts {
-                            parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id),
-                            ty: self.infcx.next_ty_var(TypeVariableOrigin {
-                                kind: TypeVariableOriginKind::MiscVariable,
-                                span,
-                            }),
-                        },
-                    )
-                    .args;
-                    let user_ty =
-                        self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
-                            def.to_def_id(),
-                            ty::UserArgs { args, user_self_ty: None },
-                        ));
-                    let annotation = ty::CanonicalUserTypeAnnotation {
-                        inferred_ty: pattern.ty,
-                        span,
-                        user_ty: Box::new(user_ty),
-                    };
-                    ascriptions.push(Ascription {
-                        annotation,
-                        source,
-                        variance: ty::Contravariant,
-                    });
-                }
-            }
-
-            PatKind::Constant { .. } => {
-                // FIXME normalize patterns when possible
-                return Err(match_pair);
-            }
-
-            PatKind::Range(ref range) => {
-                if range.is_full_range(self.tcx) != Some(true) {
-                    return Err(match_pair);
-                }
-            }
-
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                if !(prefix.is_empty() && slice.is_some() && suffix.is_empty()) {
-                    self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
-                    return Err(match_pair);
-                }
-            }
-
-            PatKind::Variant { adt_def, args, variant_index, subpatterns: _ } => {
-                let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
-                    i == variant_index || {
-                        (self.tcx.features().exhaustive_patterns
-                            || self.tcx.features().min_exhaustive_patterns)
-                            && !v
-                                .inhabited_predicate(self.tcx, adt_def)
-                                .instantiate(self.tcx, args)
-                                .apply_ignore_module(self.tcx, self.param_env)
-                    }
-                }) && (adt_def.did().is_local()
-                    || !adt_def.is_variant_list_non_exhaustive());
-                if !irrefutable {
-                    self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
-                    return Err(match_pair);
-                }
-            }
-
-            PatKind::Or { .. } => return Err(match_pair),
-        }
-
-        // Simplifiable pattern; we replace it with its subpairs.
-        match_pairs.append(&mut match_pair.subpairs);
-        Ok(())
-    }
 }
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index ae9ebe7170b..1c97de58863 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -6,7 +6,7 @@
 // the candidates based on the result.
 
 use crate::build::expr::as_place::PlaceBuilder;
-use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
+use crate::build::matches::{Candidate, MatchPair, Test, TestCase, TestKind};
 use crate::build::Builder;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::{LangItem, RangeEnd};
@@ -29,58 +29,45 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// It is a bug to call this with a not-fully-simplified pattern.
     pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
-        match match_pair.pattern.kind {
-            PatKind::Variant { adt_def, args: _, variant_index: _, subpatterns: _ } => Test {
-                span: match_pair.pattern.span,
-                kind: TestKind::Switch {
-                    adt_def,
-                    variants: BitSet::new_empty(adt_def.variants().len()),
-                },
-            },
+        let kind = match match_pair.test_case {
+            TestCase::Variant { adt_def, variant_index: _ } => {
+                TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) }
+            }
 
-            PatKind::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
+            TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
                 // For integers, we use a `SwitchInt` match, which allows
                 // us to handle more cases.
-                Test {
-                    span: match_pair.pattern.span,
-                    kind: TestKind::SwitchInt {
-                        switch_ty: match_pair.pattern.ty,
-
-                        // these maps are empty to start; cases are
-                        // added below in add_cases_to_switch
-                        options: Default::default(),
-                    },
+                TestKind::SwitchInt {
+                    switch_ty: match_pair.pattern.ty,
+
+                    // these maps are empty to start; cases are
+                    // added below in add_cases_to_switch
+                    options: Default::default(),
                 }
             }
 
-            PatKind::Constant { value } => Test {
-                span: match_pair.pattern.span,
-                kind: TestKind::Eq { value, ty: match_pair.pattern.ty },
-            },
+            TestCase::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern.ty },
 
-            PatKind::Range(ref range) => {
+            TestCase::Range(range) => {
                 assert_eq!(range.ty, match_pair.pattern.ty);
-                Test { span: match_pair.pattern.span, kind: TestKind::Range(range.clone()) }
+                TestKind::Range(Box::new(range.clone()))
             }
 
-            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
-                let len = prefix.len() + suffix.len();
-                let op = if slice.is_some() { BinOp::Ge } else { BinOp::Eq };
-                Test { span: match_pair.pattern.span, kind: TestKind::Len { len: len as u64, op } }
+            TestCase::Slice { len, variable_length } => {
+                let op = if variable_length { BinOp::Ge } else { BinOp::Eq };
+                TestKind::Len { len: len as u64, op }
             }
 
-            PatKind::Or { .. } => bug!("or-patterns should have already been handled"),
-
-            PatKind::AscribeUserType { .. }
-            | PatKind::InlineConstant { .. }
-            | PatKind::Array { .. }
-            | PatKind::Wild
-            | PatKind::Binding { .. }
-            | PatKind::Never
-            | PatKind::Leaf { .. }
-            | PatKind::Deref { .. }
-            | PatKind::Error(_) => self.error_simplifiable(match_pair),
-        }
+            TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
+
+            TestCase::Irrefutable { .. } => span_bug!(
+                match_pair.pattern.span,
+                "simplifiable pattern found: {:?}",
+                match_pair.pattern
+            ),
+        };
+
+        Test { span: match_pair.pattern.span, kind }
     }
 
     pub(super) fn add_cases_to_switch<'pat>(
@@ -94,32 +81,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             return false;
         };
 
-        match match_pair.pattern.kind {
-            PatKind::Constant { value } => {
+        match match_pair.test_case {
+            TestCase::Constant { value } => {
                 options.entry(value).or_insert_with(|| value.eval_bits(self.tcx, self.param_env));
                 true
             }
-            PatKind::Variant { .. } => {
+            TestCase::Variant { .. } => {
                 panic!("you should have called add_variants_to_switch instead!");
             }
-            PatKind::Range(ref range) => {
+            TestCase::Range(ref range) => {
                 // Check that none of the switch values are in the range.
                 self.values_not_contained_in_range(&*range, options).unwrap_or(false)
             }
-            PatKind::Slice { .. }
-            | PatKind::Array { .. }
-            | PatKind::Wild
-            | PatKind::Never
-            | PatKind::Or { .. }
-            | PatKind::Binding { .. }
-            | PatKind::AscribeUserType { .. }
-            | PatKind::InlineConstant { .. }
-            | PatKind::Leaf { .. }
-            | PatKind::Deref { .. }
-            | PatKind::Error(_) => {
-                // don't know how to add these patterns to a switch
-                false
-            }
+            // don't know how to add these patterns to a switch
+            _ => false,
         }
     }
 
@@ -134,17 +109,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             return false;
         };
 
-        match match_pair.pattern.kind {
-            PatKind::Variant { adt_def: _, variant_index, .. } => {
+        match match_pair.test_case {
+            TestCase::Variant { variant_index, .. } => {
                 // We have a pattern testing for variant `variant_index`
                 // set the corresponding index to true
                 variants.insert(variant_index);
                 true
             }
-            _ => {
-                // don't know how to add these patterns to a switch
-                false
-            }
+            // don't know how to add these patterns to a switch
+            _ => false,
         }
     }
 
@@ -591,12 +564,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?;
 
         let fully_matched;
-        let ret = match (&test.kind, &match_pair.pattern.kind) {
+        let ret = match (&test.kind, &match_pair.test_case) {
             // If we are performing a variant switch, then this
             // informs variant patterns, but nothing else.
             (
                 &TestKind::Switch { adt_def: tested_adt_def, .. },
-                &PatKind::Variant { adt_def, variant_index, .. },
+                &TestCase::Variant { adt_def, variant_index },
             ) => {
                 assert_eq!(adt_def, tested_adt_def);
                 fully_matched = true;
@@ -612,14 +585,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             //
             // FIXME(#29623) we could use PatKind::Range to rule
             // things out here, in some cases.
-            (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Constant { value })
+            (TestKind::SwitchInt { switch_ty: _, options }, TestCase::Constant { value })
                 if is_switch_ty(match_pair.pattern.ty) =>
             {
                 fully_matched = true;
                 let index = options.get_index_of(value).unwrap();
                 Some(index)
             }
-            (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Range(range)) => {
+            (TestKind::SwitchInt { switch_ty: _, options }, TestCase::Range(range)) => {
                 fully_matched = false;
                 let not_contained =
                     self.values_not_contained_in_range(&*range, options).unwrap_or(false);
@@ -637,11 +610,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             (
                 &TestKind::Len { len: test_len, op: BinOp::Eq },
-                PatKind::Slice { prefix, slice, suffix },
+                &TestCase::Slice { len, variable_length },
             ) => {
-                let pat_len = (prefix.len() + suffix.len()) as u64;
-                match (test_len.cmp(&pat_len), slice) {
-                    (Ordering::Equal, &None) => {
+                match (test_len.cmp(&(len as u64)), variable_length) {
+                    (Ordering::Equal, false) => {
                         // on true, min_len = len = $actual_length,
                         // on false, len != $actual_length
                         fully_matched = true;
@@ -654,13 +626,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         fully_matched = false;
                         Some(1)
                     }
-                    (Ordering::Equal | Ordering::Greater, &Some(_)) => {
+                    (Ordering::Equal | Ordering::Greater, true) => {
                         // This can match both if $actual_len = test_len >= pat_len,
                         // and if $actual_len > test_len. We can't advance.
                         fully_matched = false;
                         None
                     }
-                    (Ordering::Greater, &None) => {
+                    (Ordering::Greater, false) => {
                         // test_len != pat_len, so if $actual_len = test_len, then
                         // $actual_len != pat_len.
                         fully_matched = false;
@@ -670,31 +642,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             (
                 &TestKind::Len { len: test_len, op: BinOp::Ge },
-                PatKind::Slice { prefix, slice, suffix },
+                &TestCase::Slice { len, variable_length },
             ) => {
                 // the test is `$actual_len >= test_len`
-                let pat_len = (prefix.len() + suffix.len()) as u64;
-                match (test_len.cmp(&pat_len), slice) {
-                    (Ordering::Equal, &Some(_)) => {
+                match (test_len.cmp(&(len as u64)), variable_length) {
+                    (Ordering::Equal, true) => {
                         // $actual_len >= test_len = pat_len,
                         // so we can match.
                         fully_matched = true;
                         Some(0)
                     }
-                    (Ordering::Less, _) | (Ordering::Equal, &None) => {
+                    (Ordering::Less, _) | (Ordering::Equal, false) => {
                         // test_len <= pat_len. If $actual_len < test_len,
                         // then it is also < pat_len, so the test passing is
                         // necessary (but insufficient).
                         fully_matched = false;
                         Some(0)
                     }
-                    (Ordering::Greater, &None) => {
+                    (Ordering::Greater, false) => {
                         // test_len > pat_len. If $actual_len >= test_len > pat_len,
                         // then we know we won't have a match.
                         fully_matched = false;
                         Some(1)
                     }
-                    (Ordering::Greater, &Some(_)) => {
+                    (Ordering::Greater, true) => {
                         // test_len < pat_len, and is therefore less
                         // strict. This can still go both ways.
                         fully_matched = false;
@@ -703,8 +674,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
 
-            (TestKind::Range(test), PatKind::Range(pat)) => {
-                if test == pat {
+            (TestKind::Range(test), &TestCase::Range(pat)) => {
+                if test.as_ref() == pat {
                     fully_matched = true;
                     Some(0)
                 } else {
@@ -714,7 +685,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None }
                 }
             }
-            (TestKind::Range(range), &PatKind::Constant { value }) => {
+            (TestKind::Range(range), &TestCase::Constant { value }) => {
                 fully_matched = false;
                 if !range.contains(value, self.tcx, self.param_env)? {
                     // `value` is not contained in the testing range,
@@ -737,7 +708,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // However, at this point we can still encounter or-patterns that were extracted
                 // from previous calls to `sort_candidate`, so we need to manually address that
                 // case to avoid panicking in `self.test()`.
-                if let PatKind::Or { .. } = &match_pair.pattern.kind {
+                if let TestCase::Or { .. } = &match_pair.test_case {
                     return None;
                 }
 
@@ -760,18 +731,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let match_pair = candidate.match_pairs.remove(match_pair_index);
             candidate.match_pairs.extend(match_pair.subpairs);
             // Move or-patterns to the end.
-            candidate
-                .match_pairs
-                .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
+            candidate.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
         }
 
         ret
     }
 
-    fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
-        span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern)
-    }
-
     fn values_not_contained_in_range(
         &self,
         range: &PatRange<'tcx>,
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index e42d764147c..3f7e7a348ed 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,9 +1,9 @@
-use crate::build::expr::as_place::PlaceBase;
-use crate::build::expr::as_place::PlaceBuilder;
-use crate::build::matches::MatchPair;
+use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
+use crate::build::matches::{MatchPair, TestCase};
 use crate::build::Builder;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::mir::*;
-use rustc_middle::thir::*;
+use rustc_middle::thir::{self, *};
 use rustc_middle::ty;
 use rustc_middle::ty::TypeVisitableExt;
 
@@ -117,50 +117,144 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
             place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
         }
 
+        let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
         let mut subpairs = Vec::new();
-        match pattern.kind {
-            PatKind::Constant { .. }
-            | PatKind::Range(_)
-            | PatKind::Or { .. }
-            | PatKind::Never
-            | PatKind::Wild
-            | PatKind::Error(_) => {}
-
-            PatKind::AscribeUserType { ref subpattern, .. } => {
+        let test_case = match pattern.kind {
+            PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
+            PatKind::Or { .. } => TestCase::Or,
+
+            PatKind::Range(ref range) => {
+                if range.is_full_range(cx.tcx) == Some(true) {
+                    default_irrefutable()
+                } else {
+                    TestCase::Range(range)
+                }
+            }
+
+            PatKind::Constant { value } => TestCase::Constant { value },
+
+            PatKind::AscribeUserType {
+                ascription: thir::Ascription { ref annotation, variance },
+                ref subpattern,
+                ..
+            } => {
+                // Apply the type ascription to the value at `match_pair.place`
+                let ascription = place.try_to_place(cx).map(|source| super::Ascription {
+                    annotation: annotation.clone(),
+                    source,
+                    variance,
+                });
+
                 subpairs.push(MatchPair::new(place.clone(), subpattern, cx));
+                TestCase::Irrefutable { ascription, binding: None }
             }
 
-            PatKind::Binding { ref subpattern, .. } => {
+            PatKind::Binding {
+                name: _,
+                mutability: _,
+                mode,
+                var,
+                ty: _,
+                ref subpattern,
+                is_primary: _,
+            } => {
+                let binding = place.try_to_place(cx).map(|source| super::Binding {
+                    span: pattern.span,
+                    source,
+                    var_id: var,
+                    binding_mode: mode,
+                });
+
                 if let Some(subpattern) = subpattern.as_ref() {
                     // this is the `x @ P` case; have to keep matching against `P` now
                     subpairs.push(MatchPair::new(place.clone(), subpattern, cx));
                 }
+                TestCase::Irrefutable { ascription: None, binding }
             }
 
-            PatKind::InlineConstant { subpattern: ref pattern, .. } => {
+            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
+                // Apply a type ascription for the inline constant to the value at `match_pair.place`
+                let ascription = place.try_to_place(cx).map(|source| {
+                    let span = pattern.span;
+                    let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
+                    let args = ty::InlineConstArgs::new(
+                        cx.tcx,
+                        ty::InlineConstArgsParts {
+                            parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
+                            ty: cx.infcx.next_ty_var(TypeVariableOrigin {
+                                kind: TypeVariableOriginKind::MiscVariable,
+                                span,
+                            }),
+                        },
+                    )
+                    .args;
+                    let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
+                        def.to_def_id(),
+                        ty::UserArgs { args, user_self_ty: None },
+                    ));
+                    let annotation = ty::CanonicalUserTypeAnnotation {
+                        inferred_ty: pattern.ty,
+                        span,
+                        user_ty: Box::new(user_ty),
+                    };
+                    super::Ascription { annotation, source, variance: ty::Contravariant }
+                });
+
                 subpairs.push(MatchPair::new(place.clone(), pattern, cx));
+                TestCase::Irrefutable { ascription, binding: None }
             }
 
-            PatKind::Slice { ref prefix, ref slice, ref suffix }
-            | PatKind::Array { ref prefix, ref slice, ref suffix } => {
+            PatKind::Array { ref prefix, ref slice, ref suffix } => {
                 cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix);
+                default_irrefutable()
+            }
+            PatKind::Slice { ref prefix, ref slice, ref suffix } => {
+                cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix);
+
+                if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
+                    default_irrefutable()
+                } else {
+                    TestCase::Slice {
+                        len: prefix.len() + suffix.len(),
+                        variable_length: slice.is_some(),
+                    }
+                }
             }
 
-            PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
+            PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
                 let downcast_place = place.clone().downcast(adt_def, variant_index); // `(x as Variant)`
                 subpairs = cx.field_match_pairs(downcast_place, subpatterns);
+
+                let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
+                    i == variant_index || {
+                        (cx.tcx.features().exhaustive_patterns
+                            || cx.tcx.features().min_exhaustive_patterns)
+                            && !v
+                                .inhabited_predicate(cx.tcx, adt_def)
+                                .instantiate(cx.tcx, args)
+                                .apply_ignore_module(cx.tcx, cx.param_env)
+                    }
+                }) && (adt_def.did().is_local()
+                    || !adt_def.is_variant_list_non_exhaustive());
+                if irrefutable {
+                    default_irrefutable()
+                } else {
+                    TestCase::Variant { adt_def, variant_index }
+                }
             }
 
             PatKind::Leaf { ref subpatterns } => {
                 subpairs = cx.field_match_pairs(place.clone(), subpatterns);
+                default_irrefutable()
             }
 
             PatKind::Deref { ref subpattern } => {
                 let place_builder = place.clone().deref();
                 subpairs.push(MatchPair::new(place_builder, subpattern, cx));
+                default_irrefutable()
             }
-        }
+        };
 
-        MatchPair { place, pattern, subpairs }
+        MatchPair { place, test_case, subpairs, pattern }
     }
 }