about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection')
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs50
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs54
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs4
15 files changed, 156 insertions, 27 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 35f7d1d7151..8b5c029428c 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -363,6 +363,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Foreign(_)
             | ty::Str
             | ty::Array(_, _)
+            | ty::Pat(_, _)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
@@ -596,6 +597,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Foreign(_)
             | ty::Str
             | ty::Array(_, _)
+            | ty::Pat(_, _)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
@@ -684,6 +686,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Foreign(_)
             | ty::Str
             | ty::Array(_, _)
+            | ty::Pat(_, _)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 00cd4b48797..8a96d810134 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -50,7 +50,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
             Ok(vec![ty::Binder::dummy(element_ty)])
         }
 
-        ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]),
+        ty::Pat(element_ty, _) | ty::Array(element_ty, _) | ty::Slice(element_ty) => {
+            Ok(vec![ty::Binder::dummy(element_ty)])
+        }
 
         ty::Tuple(tys) => {
             // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
@@ -114,6 +116,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
         | ty::Coroutine(..)
         | ty::CoroutineWitness(..)
         | ty::Array(..)
+        | ty::Pat(..)
         | ty::Closure(..)
         | ty::CoroutineClosure(..)
         | ty::Never
@@ -177,6 +180,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         | ty::Ref(_, _, Mutability::Not)
         | ty::Array(..) => Err(NoSolution),
 
+        // Cannot implement in core, as we can't be generic over patterns yet,
+        // so we'd have to list all patterns and type combinations.
+        ty::Pat(ty, ..) => Ok(vec![ty::Binder::dummy(ty)]),
+
         ty::Dynamic(..)
         | ty::Str
         | ty::Slice(_)
@@ -347,6 +354,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         | ty::CoroutineWitness(..)
         | ty::Never
         | ty::Tuple(_)
+        | ty::Pat(_, _)
         | ty::Alias(_, _)
         | ty::Param(_)
         | ty::Placeholder(..)
@@ -526,6 +534,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
         | ty::Foreign(_)
         | ty::Str
         | ty::Array(_, _)
+        | ty::Pat(_, _)
         | ty::Slice(_)
         | ty::RawPtr(_, _)
         | ty::Ref(_, _, _)
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index fb296d55100..befde8f768a 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -533,6 +533,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 | ty::Uint(..)
                 | ty::Float(..)
                 | ty::Array(..)
+                | ty::Pat(..)
                 | ty::RawPtr(..)
                 | ty::Ref(..)
                 | ty::FnDef(..)
@@ -768,6 +769,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             | ty::Uint(..)
             | ty::Float(..)
             | ty::Array(..)
+            | ty::Pat(..)
             | ty::RawPtr(..)
             | ty::Ref(..)
             | ty::FnDef(..)
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index eb3ad0aa782..371668bf617 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -1051,6 +1051,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Float(_)
             | ty::Str
             | ty::Array(_, _)
+            | ty::Pat(_, _)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 8625ad378f7..77eaa4fd03e 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -883,6 +883,7 @@ where
             | ty::Float(..)
             | ty::Str
             | ty::FnDef(..)
+            | ty::Pat(..)
             | ty::FnPtr(_)
             | ty::Array(..)
             | ty::Slice(..)
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 10c03387a5b..837b784f272 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -40,7 +40,7 @@ pub struct ImplCandidate<'tcx> {
 
 enum GetSafeTransmuteErrorAndReason {
     Silent,
-    Error { err_msg: String, safe_transmute_explanation: String },
+    Error { err_msg: String, safe_transmute_explanation: Option<String> },
 }
 
 struct UnsatisfiedConst(pub bool);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 144971b63c0..1b8b09ddda1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -558,7 +558,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 GetSafeTransmuteErrorAndReason::Error {
                                     err_msg,
                                     safe_transmute_explanation,
-                                } => (err_msg, Some(safe_transmute_explanation)),
+                                } => (err_msg, safe_transmute_explanation),
                             }
                         } else {
                             (err_msg, None)
@@ -1804,6 +1804,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 ty::Foreign(..) => Some(19),
                 ty::CoroutineWitness(..) => Some(20),
                 ty::CoroutineClosure(..) => Some(21),
+                ty::Pat(..) => Some(22),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
@@ -3067,28 +3068,33 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             return GetSafeTransmuteErrorAndReason::Silent;
         };
 
+        let dst = trait_ref.args.type_at(0);
+        let src = trait_ref.args.type_at(1);
+        let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
+
         match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
             obligation.cause,
             src_and_dst,
             assume,
         ) {
             Answer::No(reason) => {
-                let dst = trait_ref.args.type_at(0);
-                let src = trait_ref.args.type_at(1);
-                let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
                 let safe_transmute_explanation = match reason {
                     rustc_transmute::Reason::SrcIsNotYetSupported => {
-                        format!("analyzing the transmutability of `{src}` is not yet supported.")
+                        format!("analyzing the transmutability of `{src}` is not yet supported")
                     }
 
                     rustc_transmute::Reason::DstIsNotYetSupported => {
-                        format!("analyzing the transmutability of `{dst}` is not yet supported.")
+                        format!("analyzing the transmutability of `{dst}` is not yet supported")
                     }
 
                     rustc_transmute::Reason::DstIsBitIncompatible => {
                         format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`")
                     }
 
+                    rustc_transmute::Reason::DstUninhabited => {
+                        format!("`{dst}` is uninhabited")
+                    }
+
                     rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
                         format!("`{dst}` may carry safety invariants")
                     }
@@ -3134,14 +3140,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         format!("`{dst}` has an unknown layout")
                     }
                 };
-                GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation }
+                GetSafeTransmuteErrorAndReason::Error {
+                    err_msg,
+                    safe_transmute_explanation: Some(safe_transmute_explanation),
+                }
             }
             // Should never get a Yes at this point! We already ran it before, and did not get a Yes.
             Answer::Yes => span_bug!(
                 span,
                 "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
             ),
-            other => span_bug!(span, "Unsupported rustc_transmute::Answer variant: `{other:?}`"),
+            // Reached when a different obligation (namely `Freeze`) causes the
+            // transmutability analysis to fail. In this case, silence the
+            // transmutability error message in favor of that more specific
+            // error.
+            Answer::If(_) => {
+                GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None }
+            }
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 2c8116b779b..98d5b466cd0 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -119,7 +119,9 @@ pub fn predicates_for_generics<'tcx>(
 
 /// Determines whether the type `ty` is known to meet `bound` and
 /// returns true if so. Returns false if `ty` either does not meet
-/// `bound` or is not known to meet bound.
+/// `bound` or is not known to meet bound (note that this is
+/// conservative towards *no impl*, which is the opposite of the
+/// `evaluate` methods).
 pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -127,8 +129,50 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
     def_id: DefId,
 ) -> bool {
     let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]);
-    let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, trait_ref);
-    infcx.predicate_must_hold_modulo_regions(&obligation)
+    pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref)
+}
+
+/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist?
+///
+/// Ping me on zulip if you want to use this method and need help with finding
+/// an appropriate replacement.
+#[instrument(level = "debug", skip(infcx, param_env, pred), ret)]
+fn pred_known_to_hold_modulo_regions<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    pred: impl ToPredicate<'tcx>,
+) -> bool {
+    let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
+
+    let result = infcx.evaluate_obligation_no_overflow(&obligation);
+    debug!(?result);
+
+    if result.must_apply_modulo_regions() {
+        true
+    } else if result.may_apply() {
+        // Sometimes obligations are ambiguous because the recursive evaluator
+        // is not smart enough, so we fall back to fulfillment when we're not certain
+        // that an obligation holds or not. Even still, we must make sure that
+        // the we do no inference in the process of checking this obligation.
+        let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
+        infcx.probe(|_| {
+            let ocx = ObligationCtxt::new(infcx);
+            ocx.register_obligation(obligation);
+
+            let errors = ocx.select_all_or_error();
+            match errors.as_slice() {
+                // Only known to hold if we did no inference.
+                [] => infcx.shallow_resolve(goal) == goal,
+
+                errors => {
+                    debug!(?errors);
+                    false
+                }
+            }
+        })
+    } else {
+        false
+    }
 }
 
 #[instrument(level = "debug", skip(tcx, elaborated_env))]
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 56b25b0fe6c..8d04fd45940 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1048,6 +1048,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Foreign(_)
                         | ty::Str
                         | ty::Array(..)
+                        | ty::Pat(..)
                         | ty::Slice(_)
                         | ty::RawPtr(..)
                         | ty::Ref(..)
@@ -1099,6 +1100,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Float(_)
                         | ty::Str
                         | ty::Array(..)
+                        | ty::Pat(..)
                         | ty::Slice(_)
                         | ty::RawPtr(..)
                         | ty::Ref(..)
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index aaa38d14d6e..326c68e01db 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -42,8 +42,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Foreign(..)
         | ty::Error(_) => true,
 
-        // [T; N] and [T] have same properties as T.
-        ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
+        // `T is PAT`, `[T; N]`, and `[T]` have same properties as T.
+        ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
 
         // (T1..Tn) and closures have same properties as T1..Tn --
         // check if *all* of them are trivial.
@@ -222,7 +222,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
             // these types never have a destructor
         }
 
-        ty::Array(ety, _) | ty::Slice(ety) => {
+        ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => {
             // single-element containers, behave like their element
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
                 dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints)
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index c6ea596b819..c1f340dfc7c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -670,6 +670,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Foreign(_)
                 | ty::Str
                 | ty::Array(_, _)
+                | ty::Pat(_, _)
                 | ty::Slice(_)
                 | ty::RawPtr(_, _)
                 | ty::Ref(_, _, _)
@@ -803,6 +804,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Float(_)
                 | ty::Str
                 | ty::Array(_, _)
+                | ty::Pat(_, _)
                 | ty::Slice(_)
                 | ty::Adt(..)
                 | ty::RawPtr(_, _)
@@ -1193,6 +1195,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Never
             | ty::Foreign(_)
             | ty::Array(..)
+            | ty::Pat(..)
             | ty::Slice(_)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
@@ -1270,6 +1273,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
+            | ty::Pat(_, _)
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(..)
@@ -1329,6 +1333,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Foreign(..)
             | ty::Str
             | ty::Array(..)
+            | ty::Pat(..)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 0459246553b..25ba985397e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -314,12 +314,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .flat_map(|cond| flatten_answer_tree(tcx, obligation, predicate, cond))
                     .collect(),
                 Condition::IfTransmutable { src, dst } => {
-                    let trait_def_id = obligation.predicate.def_id();
+                    let transmute_trait = obligation.predicate.def_id();
                     let assume_const = predicate.trait_ref.args.const_at(2);
-                    let make_obl = |from_ty, to_ty| {
-                        let trait_ref1 = ty::TraitRef::new(
+                    let make_transmute_obl = |from_ty, to_ty| {
+                        let trait_ref = ty::TraitRef::new(
                             tcx,
-                            trait_def_id,
+                            transmute_trait,
                             [
                                 ty::GenericArg::from(to_ty),
                                 ty::GenericArg::from(from_ty),
@@ -331,17 +331,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             obligation.cause.clone(),
                             obligation.recursion_depth + 1,
                             obligation.param_env,
-                            trait_ref1,
+                            trait_ref,
                         )
                     };
 
+                    let make_freeze_obl = |ty| {
+                        let trait_ref = ty::TraitRef::new(
+                            tcx,
+                            tcx.lang_items().freeze_trait().unwrap(),
+                            [ty::GenericArg::from(ty)],
+                        );
+                        Obligation::with_depth(
+                            tcx,
+                            obligation.cause.clone(),
+                            obligation.recursion_depth + 1,
+                            obligation.param_env,
+                            trait_ref,
+                        )
+                    };
+
+                    let mut obls = vec![];
+
+                    // If the source is a shared reference, it must be `Freeze`;
+                    // otherwise, transmuting could lead to data races.
+                    if src.mutability == Mutability::Not {
+                        obls.extend([make_freeze_obl(src.ty), make_freeze_obl(dst.ty)])
+                    }
+
                     // If Dst is mutable, check bidirectionally.
                     // For example, transmuting bool -> u8 is OK as long as you can't update that u8
                     // to be > 1, because you could later transmute the u8 back to a bool and get UB.
                     match dst.mutability {
-                        Mutability::Not => vec![make_obl(src.ty, dst.ty)],
-                        Mutability::Mut => vec![make_obl(src.ty, dst.ty), make_obl(dst.ty, src.ty)],
+                        Mutability::Not => obls.push(make_transmute_obl(src.ty, dst.ty)),
+                        Mutability::Mut => obls.extend([
+                            make_transmute_obl(src.ty, dst.ty),
+                            make_transmute_obl(dst.ty, src.ty),
+                        ]),
                     }
+
+                    obls
                 }
             }
         }
@@ -1417,7 +1445,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // These types are built-in, so we can fast-track by registering
                 // nested predicates for their constituent type(s)
-                ty::Array(ty, _) | ty::Slice(ty) => {
+                ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => {
                     stack.push(ty);
                 }
                 ty::Tuple(tys) => {
@@ -1469,7 +1497,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // If we have any other type (e.g. an ADT), just register a nested obligation
                 // since it's either not `const Drop` (and we raise an error during selection),
                 // or it's an ADT (and we need to check for a custom impl during selection)
-                _ => {
+                ty::Error(_)
+                | ty::Dynamic(..)
+                | ty::CoroutineClosure(..)
+                | ty::Param(_)
+                | ty::Bound(..)
+                | ty::Adt(..)
+                | ty::Alias(ty::Opaque | ty::Weak, _)
+                | ty::Infer(_)
+                | ty::Placeholder(_) => {
                     let predicate = self_ty.rebind(ty::TraitPredicate {
                         trait_ref: ty::TraitRef::from_lang_item(
                             self.tcx(),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5e9a28b5cce..e363119393a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2142,6 +2142,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
             ),
 
+            ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])),
+
             ty::Adt(def, args) => {
                 if let Some(sized_crit) = def.sized_constraint(self.tcx()) {
                     // (*) binder moved here
@@ -2202,6 +2204,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 Where(obligation.predicate.rebind(tys.iter().collect()))
             }
 
+            ty::Pat(ty, _) => {
+                // (*) binder moved here
+                Where(obligation.predicate.rebind(vec![ty]))
+            }
+
             ty::Coroutine(coroutine_def_id, args) => {
                 match self.tcx().coroutine_movability(coroutine_def_id) {
                     hir::Movability::Static => None,
@@ -2340,7 +2347,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 
             ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => t.rebind(vec![element_ty]),
 
-            ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]),
+            ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => t.rebind(vec![ty]),
 
             ty::Tuple(tys) => {
                 // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index b89406ca023..6778ac81aea 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -126,7 +126,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
                 return ControlFlow::Continue(());
             }
 
-            ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
+            ty::Pat(..) | ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
                 // First check all contained types and then tell the caller to continue searching.
                 return ty.super_visit_with(self);
             }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index a44a5ae0e6b..5553490542b 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -681,6 +681,10 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 // Note that we handle the len is implicitly checked while walking `arg`.
             }
 
+            ty::Pat(subty, _) => {
+                self.require_sized(subty, traits::MiscObligation);
+            }
+
             ty::Tuple(tys) => {
                 if let Some((_last, rest)) = tys.split_last() {
                     for &elem in rest {