about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs4
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs33
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs3
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs7
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs10
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs8
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs4
-rw-r--r--compiler/rustc_infer/src/infer/relate/lattice.rs8
-rw-r--r--compiler/rustc_infer/src/infer/relate/type_relating.rs8
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs10
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs2
-rw-r--r--compiler/rustc_infer/src/traits/project.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs54
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs63
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs65
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs20
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs39
-rw-r--r--compiler/rustc_traits/src/normalize_projection_ty.rs5
33 files changed, 250 insertions, 215 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 82aeca66693..238d7d0749a 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -18,6 +18,7 @@ use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_infer::infer::{
     BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin,
 };
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
@@ -40,7 +41,6 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::{DUMMY_SP, Span};
 use rustc_target::abi::{FIRST_VARIANT, FieldIdx};
-use rustc_trait_selection::traits::PredicateObligation;
 use rustc_trait_selection::traits::query::type_op::custom::{
     CustomTypeOp, scrape_region_constraints,
 };
@@ -2940,7 +2940,7 @@ impl NormalizeLocation for Location {
 pub(super) struct InstantiateOpaqueType<'tcx> {
     pub base_universe: Option<ty::UniverseIndex>,
     pub region_constraints: Option<RegionConstraintData<'tcx>>,
-    pub obligations: Vec<PredicateObligation<'tcx>>,
+    pub obligations: PredicateObligations<'tcx>,
 }
 
 impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index cfe7dd13e80..aca99b9fab1 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -402,9 +402,10 @@ impl<O: ForestObligation> ObligationForest<O> {
     }
 
     /// Returns the set of obligations that are in a pending state.
-    pub fn map_pending_obligations<P, F>(&self, f: F) -> Vec<P>
+    pub fn map_pending_obligations<P, F, R>(&self, f: F) -> R
     where
         F: Fn(&O) -> P,
+        R: FromIterator<P>,
     {
         self.nodes
             .iter()
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index 8d11328743c..5a66c31a0cc 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -1,4 +1,5 @@
 use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::Limit;
 use rustc_span::Span;
@@ -23,7 +24,7 @@ struct AutoderefSnapshot<'tcx> {
     reached_recursion_limit: bool,
     steps: Vec<(Ty<'tcx>, AutoderefKind)>,
     cur_ty: Ty<'tcx>,
-    obligations: Vec<traits::PredicateObligation<'tcx>>,
+    obligations: PredicateObligations<'tcx>,
 }
 
 pub struct Autoderef<'a, 'tcx> {
@@ -119,7 +120,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
             state: AutoderefSnapshot {
                 steps: vec![],
                 cur_ty: infcx.resolve_vars_if_possible(base_ty),
-                obligations: vec![],
+                obligations: PredicateObligations::new(),
                 at_start: true,
                 reached_recursion_limit: false,
             },
@@ -165,7 +166,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
     pub fn structurally_normalize(
         &self,
         ty: Ty<'tcx>,
-    ) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> {
+    ) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> {
         let ocx = ObligationCtxt::new(self.infcx);
         let Ok(normalized_ty) = ocx.structurally_normalize(
             &traits::ObligationCause::misc(self.span, self.body_id),
@@ -204,11 +205,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         self.state.steps.len()
     }
 
-    pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
+    pub fn into_obligations(self) -> PredicateObligations<'tcx> {
         self.state.obligations
     }
 
-    pub fn current_obligations(&self) -> Vec<traits::PredicateObligation<'tcx>> {
+    pub fn current_obligations(&self) -> PredicateObligations<'tcx> {
         self.state.obligations.clone()
     }
 
diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index d2d6da8f32b..e4ca1cee757 100644
--- a/compiler/rustc_hir_typeck/src/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
@@ -5,6 +5,7 @@ use std::iter;
 use itertools::Itertools;
 use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind};
 use rustc_infer::infer::InferOk;
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
@@ -36,10 +37,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
         let steps = autoderef.steps();
         if steps.is_empty() {
-            return InferOk { obligations: vec![], value: vec![] };
+            return InferOk { obligations: PredicateObligations::new(), value: vec![] };
         }
 
-        let mut obligations = vec![];
+        let mut obligations = PredicateObligations::new();
         let targets =
             steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false)));
         let steps: Vec<_> = steps
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index fcaa5751152..fd6ac7de14a 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -8,7 +8,7 @@ use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult};
-use rustc_infer::traits::ObligationCauseCode;
+use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
 use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::span_bug;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
@@ -805,7 +805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // [c1]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341089706
         // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796
         self.commit_if_ok(|_| {
-            let mut all_obligations = vec![];
+            let mut all_obligations = PredicateObligations::new();
             let supplied_sig = self.instantiate_binder_with_fresh_vars(
                 self.tcx.def_span(expr_def_id),
                 BoundRegionConversionTime::FnCall,
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index bd0b9870298..f81bc727aa1 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -46,6 +46,7 @@ use rustc_infer::infer::relate::RelateResult;
 use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
 use rustc_infer::traits::{
     IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation,
+    PredicateObligations,
 };
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::span_bug;
@@ -120,7 +121,7 @@ fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'
 fn success<'tcx>(
     adj: Vec<Adjustment<'tcx>>,
     target: Ty<'tcx>,
-    obligations: Vec<traits::PredicateObligation<'tcx>>,
+    obligations: PredicateObligations<'tcx>,
 ) -> CoerceResult<'tcx> {
     Ok(InferOk { value: (adj, target), obligations })
 }
@@ -184,7 +185,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // Coercing from `!` to any type is allowed:
         if a.is_never() {
             if self.coerce_never {
-                return success(simple(Adjust::NeverToAny)(b), b, vec![]);
+                return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new());
             } else {
                 // Otherwise the only coercion we can do is unification.
                 return self.unify_and(a, b, identity);
@@ -278,7 +279,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             // Two unresolved type variables: create a `Coerce` predicate.
             let target_ty = if self.use_lub { self.next_ty_var(self.cause.span) } else { b };
 
-            let mut obligations = Vec::with_capacity(2);
+            let mut obligations = PredicateObligations::with_capacity(2);
             for &source_ty in &[a, b] {
                 if source_ty != target_ty {
                     obligations.push(Obligation::new(
@@ -744,7 +745,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         // Check the obligations of the cast -- for example, when casting
         // `usize` to `dyn* Clone + 'static`:
-        let mut obligations: Vec<_> = predicates
+        let obligations = predicates
             .iter()
             .map(|predicate| {
                 // For each existential predicate (e.g., `?Self: Clone`) instantiate
@@ -764,21 +765,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                         ty::OutlivesPredicate(a, b_region),
                     ))),
                 ),
+                // Enforce that the type is `usize`/pointer-sized.
+                Obligation::new(
+                    self.tcx,
+                    self.cause.clone(),
+                    self.param_env,
+                    ty::TraitRef::new(
+                        self.tcx,
+                        self.tcx
+                            .require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)),
+                        [a],
+                    ),
+                ),
             ])
             .collect();
 
-        // Enforce that the type is `usize`/pointer-sized.
-        obligations.push(Obligation::new(
-            self.tcx,
-            self.cause.clone(),
-            self.param_env,
-            ty::TraitRef::new(
-                self.tcx,
-                self.tcx.require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)),
-                [a],
-            ),
-        ));
-
         Ok(InferOk {
             value: (
                 vec![Adjustment { kind: Adjust::Pointer(PointerCoercion::DynStar), target: b }],
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
index 2aad9a043f9..693cb4465cc 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -1,6 +1,6 @@
 //! A utility module to inspect currently ambiguous obligations in the current context.
 
-use rustc_infer::traits::{self, ObligationCause};
+use rustc_infer::traits::{self, ObligationCause, PredicateObligations};
 use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_span::Span;
@@ -15,10 +15,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Returns a list of all obligations whose self type has been unified
     /// with the unconstrained type `self_ty`.
     #[instrument(skip(self), level = "debug")]
-    pub(crate) fn obligations_for_self_ty(
-        &self,
-        self_ty: ty::TyVid,
-    ) -> Vec<traits::PredicateObligation<'tcx>> {
+    pub(crate) fn obligations_for_self_ty(&self, self_ty: ty::TyVid) -> PredicateObligations<'tcx> {
         if self.next_trait_solver() {
             self.obligations_for_self_ty_next(self_ty)
         } else {
@@ -75,10 +72,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(crate) fn obligations_for_self_ty_next(
         &self,
         self_ty: ty::TyVid,
-    ) -> Vec<traits::PredicateObligation<'tcx>> {
+    ) -> PredicateObligations<'tcx> {
         let obligations = self.fulfillment_cx.borrow().pending_obligations();
         debug!(?obligations);
-        let mut obligations_for_self_ty = vec![];
+        let mut obligations_for_self_ty = PredicateObligations::new();
         for obligation in obligations {
             let mut visitor = NestedObligationsForSelfTy {
                 fcx: self,
@@ -103,7 +100,7 @@ struct NestedObligationsForSelfTy<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     self_ty: ty::TyVid,
     root_cause: &'a ObligationCause<'tcx>,
-    obligations_for_self_ty: &'a mut Vec<traits::PredicateObligation<'tcx>>,
+    obligations_for_self_ty: &'a mut PredicateObligations<'tcx>,
 }
 
 impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index cb8b1df2c6e..2de5947b16f 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -12,6 +12,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{self, InferOk};
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{
@@ -412,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
-        let mut obligations = vec![];
+        let mut obligations = PredicateObligations::new();
 
         // FIXME(effects): revisit when binops get `#[const_trait]`
 
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 7791bd73628..1d3d32ef749 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -28,7 +28,8 @@ use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult};
 use crate::traits::query::NoSolution;
 use crate::traits::{
-    Obligation, ObligationCause, PredicateObligation, ScrubbedTraitError, TraitEngine,
+    Obligation, ObligationCause, PredicateObligation, PredicateObligations, ScrubbedTraitError,
+    TraitEngine,
 };
 
 impl<'tcx> InferCtxt<'tcx> {
@@ -493,7 +494,7 @@ impl<'tcx> InferCtxt<'tcx> {
             ),
         };
 
-        let mut obligations = vec![];
+        let mut obligations = PredicateObligations::new();
 
         // Carry all newly resolved opaque types to the caller's scope
         for &(a, b) in &query_response.value.opaque_types {
@@ -598,7 +599,7 @@ impl<'tcx> InferCtxt<'tcx> {
         variables1: &OriginalQueryValues<'tcx>,
         variables2: impl Fn(BoundVar) -> GenericArg<'tcx>,
     ) -> InferResult<'tcx, ()> {
-        let mut obligations = vec![];
+        let mut obligations = PredicateObligations::new();
         for (index, value1) in variables1.var_values.iter().enumerate() {
             let value2 = variables2(BoundVar::new(index));
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index bc813305ba4..7ef714475fc 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -50,7 +50,9 @@ use tracing::{debug, instrument};
 use type_variable::TypeVariableOrigin;
 
 use crate::infer::region_constraints::UndoLog;
-use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
+use crate::traits::{
+    self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine,
+};
 
 pub mod at;
 pub mod canonical;
@@ -68,7 +70,7 @@ pub(crate) mod snapshot;
 mod type_variable;
 
 /// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper
-/// around `Vec<PredicateObligation<'tcx>>`, but it has one important property:
+/// around `PredicateObligations<'tcx>`, but it has one important property:
 /// because `InferOk` is marked with `#[must_use]`, if you have a method
 /// `InferCtxt::f` that returns `InferResult<'tcx, ()>` and you call it with
 /// `infcx.f()?;` you'll get a warning about the obligations being discarded
@@ -78,7 +80,7 @@ mod type_variable;
 #[derive(Debug)]
 pub struct InferOk<'tcx, T> {
     pub value: T,
-    pub obligations: Vec<PredicateObligation<'tcx>>,
+    pub obligations: PredicateObligations<'tcx>,
 }
 pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
 
@@ -658,7 +660,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
 }
 
 impl<'tcx> InferOk<'tcx, ()> {
-    pub fn into_obligations(self) -> Vec<PredicateObligation<'tcx>> {
+    pub fn into_obligations(self) -> PredicateObligations<'tcx> {
         self.obligations
     }
 }
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 365ddaba138..853ae6d2641 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -16,7 +16,7 @@ use tracing::{debug, instrument};
 use super::DefineOpaqueTypes;
 use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{InferCtxt, InferOk};
-use crate::traits::{self, Obligation};
+use crate::traits::{self, Obligation, PredicateObligations};
 
 mod table;
 
@@ -46,14 +46,14 @@ impl<'tcx> InferCtxt<'tcx> {
     ) -> InferOk<'tcx, T> {
         // We handle opaque types differently in the new solver.
         if self.next_trait_solver() {
-            return InferOk { value, obligations: vec![] };
+            return InferOk { value, obligations: PredicateObligations::new() };
         }
 
         if !value.has_opaque_types() {
-            return InferOk { value, obligations: vec![] };
+            return InferOk { value, obligations: PredicateObligations::new() };
         }
 
-        let mut obligations = vec![];
+        let mut obligations = PredicateObligations::new();
         let value = value.fold_with(&mut BottomUpFolder {
             tcx: self.tcx,
             lt_op: |lt| lt,
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index b78f9d49268..1bee9632110 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -2,7 +2,7 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, Ty};
 
 use super::InferCtxt;
-use crate::traits::{Obligation, PredicateObligation};
+use crate::traits::{Obligation, PredicateObligations};
 
 impl<'tcx> InferCtxt<'tcx> {
     /// Instead of normalizing an associated type projection,
@@ -17,7 +17,7 @@ impl<'tcx> InferCtxt<'tcx> {
         projection_ty: ty::AliasTy<'tcx>,
         cause: ObligationCause<'tcx>,
         recursion_depth: usize,
-        obligations: &mut Vec<PredicateObligation<'tcx>>,
+        obligations: &mut PredicateObligations<'tcx>,
     ) -> Ty<'tcx> {
         debug_assert!(!self.next_trait_solver());
         let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index 7eb61abfbc1..4eb77a99be7 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -27,7 +27,7 @@ use tracing::{debug, instrument};
 use super::StructurallyRelateAliases;
 use super::combine::PredicateEmittingRelation;
 use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace};
-use crate::traits::{Obligation, PredicateObligation};
+use crate::traits::{Obligation, PredicateObligations};
 
 #[derive(Clone, Copy)]
 pub(crate) enum LatticeOpKind {
@@ -52,7 +52,7 @@ pub(crate) struct LatticeOp<'infcx, 'tcx> {
     param_env: ty::ParamEnv<'tcx>,
     // Mutable fields
     kind: LatticeOpKind,
-    obligations: Vec<PredicateObligation<'tcx>>,
+    obligations: PredicateObligations<'tcx>,
 }
 
 impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> {
@@ -62,10 +62,10 @@ impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         kind: LatticeOpKind,
     ) -> LatticeOp<'infcx, 'tcx> {
-        LatticeOp { infcx, trace, param_env, kind, obligations: vec![] }
+        LatticeOp { infcx, trace, param_env, kind, obligations: PredicateObligations::new() }
     }
 
-    pub(crate) fn into_obligations(self) -> Vec<PredicateObligation<'tcx>> {
+    pub(crate) fn into_obligations(self) -> PredicateObligations<'tcx> {
         self.obligations
     }
 }
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index 35103c070c2..009271a8378 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -11,7 +11,7 @@ use tracing::{debug, instrument};
 use crate::infer::BoundRegionConversionTime::HigherRankedType;
 use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases};
 use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TypeTrace};
-use crate::traits::{Obligation, PredicateObligation};
+use crate::traits::{Obligation, PredicateObligations};
 
 /// Enforce that `a` is equal to or a subtype of `b`.
 pub(crate) struct TypeRelating<'infcx, 'tcx> {
@@ -24,7 +24,7 @@ pub(crate) struct TypeRelating<'infcx, 'tcx> {
 
     // Mutable fields.
     ambient_variance: ty::Variance,
-    obligations: Vec<PredicateObligation<'tcx>>,
+    obligations: PredicateObligations<'tcx>,
     /// The cache only tracks the `ambient_variance` as it's the
     /// only field which is mutable and which meaningfully changes
     /// the result when relating types.
@@ -65,12 +65,12 @@ impl<'infcx, 'tcx> TypeRelating<'infcx, 'tcx> {
             param_env,
             define_opaque_types,
             ambient_variance,
-            obligations: vec![],
+            obligations: PredicateObligations::new(),
             cache: Default::default(),
         }
     }
 
-    pub(crate) fn into_obligations(self) -> Vec<PredicateObligation<'tcx>> {
+    pub(crate) fn into_obligations(self) -> PredicateObligations<'tcx> {
         self.obligations
     }
 }
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index a076cdad672..ba1516655b0 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -3,7 +3,7 @@ use std::fmt::Debug;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, Ty, Upcast};
 
-use super::{ObligationCause, PredicateObligation};
+use super::{ObligationCause, PredicateObligation, PredicateObligations};
 use crate::infer::InferCtxt;
 use crate::traits::Obligation;
 
@@ -20,7 +20,7 @@ pub enum ScrubbedTraitError<'tcx> {
     /// An ambiguity. This goal may hold if further inference is done.
     Ambiguity,
     /// An old-solver-style cycle error, which will fatal.
-    Cycle(Vec<PredicateObligation<'tcx>>),
+    Cycle(PredicateObligations<'tcx>),
 }
 
 impl<'tcx> ScrubbedTraitError<'tcx> {
@@ -62,7 +62,7 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
     fn register_predicate_obligations(
         &mut self,
         infcx: &InferCtxt<'tcx>,
-        obligations: Vec<PredicateObligation<'tcx>>,
+        obligations: PredicateObligations<'tcx>,
     ) {
         for obligation in obligations {
             self.register_predicate_obligation(infcx, obligation);
@@ -84,7 +84,7 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
         self.collect_remaining_errors(infcx)
     }
 
-    fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
+    fn pending_obligations(&self) -> PredicateObligations<'tcx>;
 
     /// Among all pending obligations, collect those are stalled on a inference variable which has
     /// changed since the last call to `select_where_possible`. Those obligations are marked as
@@ -92,7 +92,7 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
     fn drain_unstalled_obligations(
         &mut self,
         infcx: &InferCtxt<'tcx>,
-    ) -> Vec<PredicateObligation<'tcx>>;
+    ) -> PredicateObligations<'tcx>;
 }
 
 pub trait FromSolverError<'tcx, E>: Debug + 'tcx {
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 34b0fe3e967..2d02391c57a 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -84,6 +84,8 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
 pub type TraitObligation<'tcx> = Obligation<'tcx, ty::TraitPredicate<'tcx>>;
 pub type PolyTraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
 
+pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
+
 impl<'tcx> PredicateObligation<'tcx> {
     /// Flips the polarity of the inner predicate.
     ///
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index 64b72de3986..cab2ce9f5a0 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -6,7 +6,7 @@ use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty;
 use tracing::{debug, info};
 
-use super::PredicateObligation;
+use super::PredicateObligations;
 use crate::infer::snapshot::undo_log::InferCtxtUndoLogs;
 
 pub(crate) type UndoLog<'tcx> =
@@ -20,7 +20,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
 #[derive(Clone)]
 pub struct Normalized<'tcx, T> {
     pub value: T,
-    pub obligations: Vec<PredicateObligation<'tcx>>,
+    pub obligations: PredicateObligations<'tcx>,
 }
 
 pub type NormalizedTerm<'tcx> = Normalized<'tcx, ty::Term<'tcx>>;
@@ -191,7 +191,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
                 info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
                 let mut ty = ty.clone();
                 if result.must_apply_considering_regions() {
-                    ty.obligations = vec![];
+                    ty.obligations = PredicateObligations::new();
                 }
                 map.insert(key, ProjectionCacheEntry::NormalizedTerm {
                     ty,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/mod.rs
index cb7efeaae0b..82695688ae8 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/mod.rs
@@ -2,7 +2,7 @@ use std::ops::Deref;
 
 use rustc_errors::DiagCtxtHandle;
 use rustc_infer::infer::InferCtxt;
-use rustc_infer::traits::PredicateObligation;
+use rustc_infer::traits::PredicateObligations;
 use rustc_macros::extension;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, Ty};
@@ -28,8 +28,7 @@ pub struct TypeErrCtxt<'a, 'tcx> {
 
     pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
 
-    pub autoderef_steps:
-        Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
+    pub autoderef_steps: Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, PredicateObligations<'tcx>)> + 'a>,
 }
 
 #[extension(pub trait InferCtxtErrorExt<'tcx>)]
@@ -45,7 +44,7 @@ impl<'tcx> InferCtxt<'tcx> {
             normalize_fn_sig: Box::new(|fn_sig| fn_sig),
             autoderef_steps: Box::new(|ty| {
                 debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck");
-                vec![(ty, vec![])]
+                vec![(ty, PredicateObligations::new())]
             }),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 081d7a6a769..8ec4427091d 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -7,7 +7,7 @@ use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
 use rustc_infer::traits::{
     self, FromSolverError, MismatchedProjectionTypes, Obligation, ObligationCause,
-    ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine,
+    ObligationCauseCode, PredicateObligation, PredicateObligations, SelectionError, TraitEngine,
 };
 use rustc_middle::bug;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -49,8 +49,8 @@ struct ObligationStorage<'tcx> {
     /// We cannot eagerly return these as error so we instead store them here
     /// to avoid recomputing them each time `select_where_possible` is called.
     /// This also allows us to return the correct `FulfillmentError` for them.
-    overflowed: Vec<PredicateObligation<'tcx>>,
-    pending: Vec<PredicateObligation<'tcx>>,
+    overflowed: PredicateObligations<'tcx>,
+    pending: PredicateObligations<'tcx>,
 }
 
 impl<'tcx> ObligationStorage<'tcx> {
@@ -58,13 +58,13 @@ impl<'tcx> ObligationStorage<'tcx> {
         self.pending.push(obligation);
     }
 
-    fn clone_pending(&self) -> Vec<PredicateObligation<'tcx>> {
+    fn clone_pending(&self) -> PredicateObligations<'tcx> {
         let mut obligations = self.pending.clone();
         obligations.extend(self.overflowed.iter().cloned());
         obligations
     }
 
-    fn take_pending(&mut self) -> Vec<PredicateObligation<'tcx>> {
+    fn take_pending(&mut self) -> PredicateObligations<'tcx> {
         let mut obligations = mem::take(&mut self.pending);
         obligations.append(&mut self.overflowed);
         obligations
@@ -197,14 +197,11 @@ where
         errors
     }
 
-    fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
+    fn pending_obligations(&self) -> PredicateObligations<'tcx> {
         self.obligations.clone_pending()
     }
 
-    fn drain_unstalled_obligations(
-        &mut self,
-        _: &InferCtxt<'tcx>,
-    ) -> Vec<PredicateObligation<'tcx>> {
+    fn drain_unstalled_obligations(&mut self, _: &InferCtxt<'tcx>) -> PredicateObligations<'tcx> {
         self.obligations.take_pending()
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index b29e41beab5..f4a2483cebf 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -11,6 +11,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::bug;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
@@ -279,7 +280,7 @@ fn equate_impl_headers<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     impl1: &ty::ImplHeader<'tcx>,
     impl2: &ty::ImplHeader<'tcx>,
-) -> Option<Vec<PredicateObligation<'tcx>>> {
+) -> Option<PredicateObligations<'tcx>> {
     let result =
         match (impl1.trait_ref, impl2.trait_ref) {
             (Some(impl1_ref), Some(impl2_ref)) => infcx
@@ -491,7 +492,7 @@ fn plug_infer_with_placeholders<'tcx>(
                 else {
                     bug!("we always expect to be able to plug an infer var with placeholder")
                 };
-                assert_eq!(obligations, &[]);
+                assert_eq!(obligations.len(), 0);
             } else {
                 ty.super_visit_with(self);
             }
@@ -514,7 +515,7 @@ fn plug_infer_with_placeholders<'tcx>(
                 else {
                     bug!("we always expect to be able to plug an infer var with placeholder")
                 };
-                assert_eq!(obligations, &[]);
+                assert_eq!(obligations.len(), 0);
             } else {
                 ct.super_visit_with(self);
             }
@@ -545,7 +546,7 @@ fn plug_infer_with_placeholders<'tcx>(
                     else {
                         bug!("we always expect to be able to plug an infer var with placeholder")
                     };
-                    assert_eq!(obligations, &[]);
+                    assert_eq!(obligations.len(), 0);
                 }
             }
         }
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index d562692c1a8..eda3f6e8023 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -10,6 +10,7 @@ use rustc_infer::infer::canonical::{
 };
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace};
+use rustc_infer::traits::PredicateObligations;
 use rustc_macros::extension;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::traits::query::NoSolution;
@@ -208,7 +209,7 @@ where
     /// getting ignored. You can make a new `ObligationCtxt` if this
     /// needs to be done in a loop, for example.
     #[must_use]
-    pub fn into_pending_obligations(self) -> Vec<PredicateObligation<'tcx>> {
+    pub fn into_pending_obligations(self) -> PredicateObligations<'tcx> {
         self.engine.borrow().pending_obligations()
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 33b8cf03701..3e3834a11c6 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -6,7 +6,8 @@ use rustc_data_structures::obligation_forest::{
 };
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::{
-    FromSolverError, PolyTraitObligation, ProjectionCacheKey, SelectionError, TraitEngine,
+    FromSolverError, PolyTraitObligation, PredicateObligations, ProjectionCacheKey, SelectionError,
+    TraitEngine,
 };
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -27,6 +28,8 @@ use crate::traits::normalize::normalize_with_depth_to;
 use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 
+pub(crate) type PendingPredicateObligations<'tcx> = Vec<PendingPredicateObligation<'tcx>>;
+
 impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
     /// Note that we include both the `ParamEnv` and the `Predicate`,
     /// as the `ParamEnv` can influence whether fulfillment succeeds
@@ -161,15 +164,16 @@ where
     fn drain_unstalled_obligations(
         &mut self,
         infcx: &InferCtxt<'tcx>,
-    ) -> Vec<PredicateObligation<'tcx>> {
-        let mut processor = DrainProcessor { removed_predicates: Vec::new(), infcx };
+    ) -> PredicateObligations<'tcx> {
+        let mut processor =
+            DrainProcessor { removed_predicates: PredicateObligations::new(), infcx };
         let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor);
         assert!(outcome.errors.is_empty());
         return processor.removed_predicates;
 
         struct DrainProcessor<'a, 'tcx> {
             infcx: &'a InferCtxt<'tcx>,
-            removed_predicates: Vec<PredicateObligation<'tcx>>,
+            removed_predicates: PredicateObligations<'tcx>,
         }
 
         impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> {
@@ -190,7 +194,7 @@ where
             ) -> ProcessResult<PendingPredicateObligation<'tcx>, !> {
                 assert!(self.needs_process_obligation(pending_obligation));
                 self.removed_predicates.push(pending_obligation.obligation.clone());
-                ProcessResult::Changed(vec![])
+                ProcessResult::Changed(Default::default())
             }
 
             fn process_backedge<'c, I>(
@@ -207,7 +211,7 @@ where
         }
     }
 
-    fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
+    fn pending_obligations(&self) -> PredicateObligations<'tcx> {
         self.predicates.map_pending_obligations(|o| o.obligation.clone())
     }
 }
@@ -216,7 +220,7 @@ struct FulfillProcessor<'a, 'tcx> {
     selcx: SelectionContext<'a, 'tcx>,
 }
 
-fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> {
+fn mk_pending<'tcx>(os: PredicateObligations<'tcx>) -> PendingPredicateObligations<'tcx> {
     os.into_iter()
         .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] })
         .collect()
@@ -321,7 +325,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
         let infcx = self.selcx.infcx;
 
         if obligation.predicate.has_aliases() {
-            let mut obligations = Vec::new();
+            let mut obligations = PredicateObligations::new();
             let predicate = normalize_with_depth_to(
                 &mut self.selcx,
                 obligation.param_env,
@@ -369,7 +373,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
                 | ty::PredicateKind::ConstEquate(..) => {
                     let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder));
-                    ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
+                    let mut obligations = PredicateObligations::with_capacity(1);
+                    obligations.push(obligation.with(infcx.tcx, pred));
+
+                    ProcessResult::Changed(mk_pending(obligations))
                 }
                 ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
                 ty::PredicateKind::NormalizesTo(..) => {
@@ -395,7 +402,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
                     }
 
-                    ProcessResult::Changed(vec![])
+                    ProcessResult::Changed(Default::default())
                 }
 
                 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
@@ -405,7 +412,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     if infcx.considering_regions {
                         infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause);
                     }
-                    ProcessResult::Changed(vec![])
+                    ProcessResult::Changed(Default::default())
                 }
 
                 ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => {
@@ -422,7 +429,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     if !self.selcx.tcx().is_dyn_compatible(trait_def_id) {
                         ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented))
                     } else {
-                        ProcessResult::Changed(vec![])
+                        ProcessResult::Changed(Default::default())
                     }
                 }
 
@@ -451,7 +458,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                             pending_obligation.stalled_on.extend([var]);
                             return ProcessResult::Unchanged;
                         }
-                        ty::ConstKind::Error(_) => return ProcessResult::Changed(vec![]),
+                        ty::ConstKind::Error(_) => {
+                            return ProcessResult::Changed(PendingPredicateObligations::new());
+                        }
                         ty::ConstKind::Value(ty, _) => ty,
                         ty::ConstKind::Unevaluated(uv) => {
                             infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
@@ -460,7 +469,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         // `<lhs_ty as Add<rhs_ty>>::Output` when this is an `Expr` representing
                         // `lhs + rhs`.
                         ty::ConstKind::Expr(_) => {
-                            return ProcessResult::Changed(mk_pending(vec![]));
+                            return ProcessResult::Changed(mk_pending(PredicateObligations::new()));
                         }
                         ty::ConstKind::Placeholder(_) => {
                             bug!("placeholder const {:?} in old solver", ct)
@@ -568,7 +577,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                         obligation.param_env,
                         obligation.cause.span,
                     ) {
-                        Ok(()) => ProcessResult::Changed(vec![]),
+                        Ok(()) => ProcessResult::Changed(Default::default()),
                         Err(NotConstEvaluatable::MentionsInfer) => {
                             pending_obligation.stalled_on.clear();
                             pending_obligation.stalled_on.extend(
@@ -722,7 +731,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
             debug!("process_child_obligations: coinductive match");
             Ok(())
         } else {
-            let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
+            let cycle = cycle.map(|c| c.obligation.clone()).collect();
             Err(FulfillmentErrorCode::Cycle(cycle))
         }
     }
@@ -745,7 +754,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
                     "selecting trait at depth {} evaluated to holds",
                     obligation.recursion_depth
                 );
-                return ProcessResult::Changed(vec![]);
+                return ProcessResult::Changed(Default::default());
             }
         }
 
@@ -809,7 +818,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
                         .projection_cache()
                         .complete(key, EvaluationResult::EvaluatedToOk);
                 }
-                return ProcessResult::Changed(vec![]);
+                return ProcessResult::Changed(Default::default());
             } else {
                 debug!("Does NOT hold: {:?}", obligation);
             }
@@ -826,9 +835,12 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
                 ProcessResult::Unchanged
             }
             // Let the caller handle the recursion
-            ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![
-                project_obligation.with(tcx, project_obligation.predicate),
-            ])),
+            ProjectAndUnifyResult::Recursive => {
+                let mut obligations = PredicateObligations::with_capacity(1);
+                obligations.push(project_obligation.with(tcx, project_obligation.predicate));
+
+                ProcessResult::Changed(mk_pending(obligations))
+            }
             ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
                 ProcessResult::Error(FulfillmentErrorCode::Project(e))
             }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 655bef0bab7..0fb795fc184 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -114,7 +114,7 @@ impl<'tcx> Debug for FulfillmentError<'tcx> {
 pub enum FulfillmentErrorCode<'tcx> {
     /// Inherently impossible to fulfill; this trait is implemented if and only
     /// if it is already implemented.
-    Cycle(Vec<PredicateObligation<'tcx>>),
+    Cycle(PredicateObligations<'tcx>),
     Select(SelectionError<'tcx>),
     Project(MismatchedProjectionTypes<'tcx>),
     Subtype(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index a7130cbd28f..7eac3559348 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::at::At;
 use rustc_infer::traits::{
-    FromSolverError, Normalized, Obligation, PredicateObligation, TraitEngine,
+    FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
 };
 use rustc_macros::extension;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal};
@@ -29,7 +29,7 @@ impl<'tcx> At<'_, 'tcx> {
     /// projection may be fallible.
     fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
         if self.infcx.next_trait_solver() {
-            InferOk { value, obligations: Vec::new() }
+            InferOk { value, obligations: PredicateObligations::new() }
         } else {
             let mut selcx = SelectionContext::new(self.infcx);
             let Normalized { value, obligations } =
@@ -83,7 +83,7 @@ pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
 where
     T: TypeFoldable<TyCtxt<'tcx>>,
 {
-    let mut obligations = Vec::new();
+    let mut obligations = PredicateObligations::new();
     let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
     Normalized { value, obligations }
 }
@@ -95,14 +95,14 @@ pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
     cause: ObligationCause<'tcx>,
     depth: usize,
     value: T,
-    obligations: &mut Vec<PredicateObligation<'tcx>>,
+    obligations: &mut PredicateObligations<'tcx>,
 ) -> T
 where
     T: TypeFoldable<TyCtxt<'tcx>>,
 {
     debug!(obligations.len = obligations.len());
     let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
-    let result = ensure_sufficient_stack(|| normalizer.fold(value));
+    let result = ensure_sufficient_stack(|| AssocTypeNormalizer::fold(&mut normalizer, value));
     debug!(?result, obligations.len = normalizer.obligations.len());
     debug!(?normalizer.obligations,);
     result
@@ -128,7 +128,7 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> {
     selcx: &'a mut SelectionContext<'b, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     cause: ObligationCause<'tcx>,
-    obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+    obligations: &'a mut PredicateObligations<'tcx>,
     depth: usize,
     universes: Vec<Option<ty::UniverseIndex>>,
 }
@@ -139,7 +139,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         cause: ObligationCause<'tcx>,
         depth: usize,
-        obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+        obligations: &'a mut PredicateObligations<'tcx>,
     ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
         debug_assert!(!selcx.infcx.next_trait_solver());
         AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index f1faff2c036..339e4bf1f22 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -77,7 +77,7 @@ fn implied_outlives_bounds<'a, 'tcx>(
     else {
         return vec![];
     };
-    assert_eq!(&obligations, &[]);
+    assert_eq!(obligations.len(), 0);
 
     // Because of #109628, we may have unexpected placeholders. Ignore them!
     // FIXME(#109628): panic in this case once the issue is fixed.
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 9cd99d99fc3..7f7c9bced18 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -9,7 +9,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
-use rustc_infer::traits::ObligationCauseCode;
+use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
 pub use rustc_middle::traits::Reveal;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
@@ -146,7 +146,7 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
 /// of the old return type, which was:
 /// ```ignore (not-rust)
 /// Result<
-///     Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
+///     Result<Option<PredicateObligations<'tcx>>, InProgress>,
 ///     MismatchedProjectionTypes<'tcx>,
 /// >
 /// ```
@@ -155,7 +155,7 @@ pub(super) enum ProjectAndUnifyResult<'tcx> {
     /// projection cannot be normalized because the required trait bound does
     /// not hold, this is returned, with `obligations` being a predicate that
     /// cannot be proven.
-    Holds(Vec<PredicateObligation<'tcx>>),
+    Holds(PredicateObligations<'tcx>),
     /// The projection cannot be normalized due to ambiguity. Resolving some
     /// inference variables in the projection may fix this.
     FailedNormalization,
@@ -231,7 +231,7 @@ fn project_and_unify_term<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionObligation<'tcx>,
 ) -> ProjectAndUnifyResult<'tcx> {
-    let mut obligations = vec![];
+    let mut obligations = PredicateObligations::new();
 
     let infcx = selcx.infcx;
     let normalized = match opt_normalize_projection_term(
@@ -289,7 +289,7 @@ pub fn normalize_projection_ty<'a, 'b, 'tcx>(
     projection_ty: ty::AliasTy<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize,
-    obligations: &mut Vec<PredicateObligation<'tcx>>,
+    obligations: &mut PredicateObligations<'tcx>,
 ) -> Term<'tcx> {
     opt_normalize_projection_term(
         selcx,
@@ -330,7 +330,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
     projection_term: ty::AliasTerm<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize,
-    obligations: &mut Vec<PredicateObligation<'tcx>>,
+    obligations: &mut PredicateObligations<'tcx>,
 ) -> Result<Option<Term<'tcx>>, InProgress> {
     let infcx = selcx.infcx;
     debug_assert!(!selcx.infcx.next_trait_solver());
@@ -452,7 +452,8 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
             Ok(Some(result.value))
         }
         Ok(Projected::NoProgress(projected_ty)) => {
-            let result = Normalized { value: projected_ty, obligations: vec![] };
+            let result =
+                Normalized { value: projected_ty, obligations: PredicateObligations::new() };
             if use_cache {
                 infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
             }
@@ -519,13 +520,14 @@ fn normalize_to_error<'a, 'tcx>(
             selcx.infcx.next_const_var(cause.span).into()
         }
     };
-    let trait_obligation = Obligation {
+    let mut obligations = PredicateObligations::new();
+    obligations.push(Obligation {
         cause,
         recursion_depth: depth,
         param_env,
         predicate: trait_ref.upcast(selcx.tcx()),
-    };
-    Normalized { value: new_value, obligations: vec![trait_obligation] }
+    });
+    Normalized { value: new_value, obligations }
 }
 
 /// Confirm and normalize the given inherent projection.
@@ -536,7 +538,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
     alias_ty: ty::AliasTy<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize,
-    obligations: &mut Vec<PredicateObligation<'tcx>>,
+    obligations: &mut PredicateObligations<'tcx>,
 ) -> Ty<'tcx> {
     let tcx = selcx.tcx();
 
@@ -604,7 +606,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
     alias_ty: ty::AliasTy<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize,
-    obligations: &mut Vec<PredicateObligation<'tcx>>,
+    obligations: &mut PredicateObligations<'tcx>,
 ) -> ty::GenericArgsRef<'tcx> {
     let tcx = selcx.tcx();
 
@@ -657,15 +659,15 @@ enum Projected<'tcx> {
 
 struct Progress<'tcx> {
     term: ty::Term<'tcx>,
-    obligations: Vec<PredicateObligation<'tcx>>,
+    obligations: PredicateObligations<'tcx>,
 }
 
 impl<'tcx> Progress<'tcx> {
     fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
-        Progress { term: Ty::new_error(tcx, guar).into(), obligations: vec![] }
+        Progress { term: Ty::new_error(tcx, guar).into(), obligations: PredicateObligations::new() }
     }
 
-    fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
+    fn with_addl_obligations(mut self, mut obligations: PredicateObligations<'tcx>) -> Self {
         self.obligations.append(&mut obligations);
         self
     }
@@ -1351,7 +1353,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
 fn confirm_coroutine_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    nested: Vec<PredicateObligation<'tcx>>,
+    nested: PredicateObligations<'tcx>,
 ) -> Progress<'tcx> {
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
     let ty::Coroutine(_, args) = self_ty.kind() else {
@@ -1410,7 +1412,7 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
 fn confirm_future_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    nested: Vec<PredicateObligation<'tcx>>,
+    nested: PredicateObligations<'tcx>,
 ) -> Progress<'tcx> {
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
     let ty::Coroutine(_, args) = self_ty.kind() else {
@@ -1458,7 +1460,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
 fn confirm_iterator_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    nested: Vec<PredicateObligation<'tcx>>,
+    nested: PredicateObligations<'tcx>,
 ) -> Progress<'tcx> {
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
     let ty::Coroutine(_, args) = self_ty.kind() else {
@@ -1504,7 +1506,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
 fn confirm_async_iterator_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    nested: Vec<PredicateObligation<'tcx>>,
+    nested: PredicateObligations<'tcx>,
 ) -> Progress<'tcx> {
     let ty::Coroutine(_, args) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
     else {
@@ -1558,7 +1560,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
 fn confirm_builtin_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    data: Vec<PredicateObligation<'tcx>>,
+    data: PredicateObligations<'tcx>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
     let self_ty = obligation.predicate.self_ty();
@@ -1569,17 +1571,17 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
         let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None);
         assert_eq!(discriminant_def_id, item_def_id);
 
-        (self_ty.discriminant_ty(tcx).into(), Vec::new())
+        (self_ty.discriminant_ty(tcx).into(), PredicateObligations::new())
     } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) {
         let destructor_def_id = tcx.associated_item_def_ids(trait_def_id)[0];
         assert_eq!(destructor_def_id, item_def_id);
 
-        (self_ty.async_destructor_ty(tcx).into(), Vec::new())
+        (self_ty.async_destructor_ty(tcx).into(), PredicateObligations::new())
     } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) {
         let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
         assert_eq!(metadata_def_id, item_def_id);
 
-        let mut obligations = Vec::new();
+        let mut obligations = PredicateObligations::new();
         let normalize = |ty| {
             normalize_with_depth_to(
                 selcx,
@@ -1627,7 +1629,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
 fn confirm_fn_pointer_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    nested: Vec<PredicateObligation<'tcx>>,
+    nested: PredicateObligations<'tcx>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
     let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
@@ -1663,7 +1665,7 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
 fn confirm_closure_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    nested: Vec<PredicateObligation<'tcx>>,
+    nested: PredicateObligations<'tcx>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
@@ -1782,7 +1784,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
 fn confirm_async_closure_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    nested: Vec<PredicateObligation<'tcx>>,
+    nested: PredicateObligations<'tcx>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
@@ -1934,7 +1936,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
 fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    nested: Vec<PredicateObligation<'tcx>>,
+    nested: PredicateObligations<'tcx>,
 ) -> Progress<'tcx> {
     let [
         // We already checked that the goal_kind >= closure_kind
@@ -1987,7 +1989,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
     );
 
     let cache_projection = cache_entry.projection_term;
-    let mut nested_obligations = Vec::new();
+    let mut nested_obligations = PredicateObligations::new();
     let obligation_projection = obligation.predicate;
     let obligation_projection = ensure_sufficient_stack(|| {
         normalize_with_depth_to(
@@ -2034,7 +2036,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
             );
             debug!("confirm_param_env_candidate: {}", msg);
             let err = Ty::new_error_with_message(infcx.tcx, obligation.cause.span, msg);
-            Progress { term: err.into(), obligations: vec![] }
+            Progress { term: err.into(), obligations: PredicateObligations::new() }
         }
     }
 }
@@ -2047,6 +2049,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     let tcx = selcx.tcx();
 
     let ImplSourceUserDefinedData { impl_def_id, args, mut nested } = impl_impl_source;
+
     let assoc_item_id = obligation.predicate.def_id;
     let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
 
@@ -2102,7 +2105,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
 fn assoc_ty_own_obligations<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTermObligation<'tcx>,
-    nested: &mut Vec<PredicateObligation<'tcx>>,
+    nested: &mut PredicateObligations<'tcx>,
 ) {
     let tcx = selcx.tcx();
     let predicates = tcx
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 36b24eac5c4..18412b844ff 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -4,6 +4,7 @@
 
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_infer::traits::PredicateObligations;
 use rustc_macros::extension;
 pub use rustc_middle::traits::query::NormalizationResult;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
@@ -20,8 +21,7 @@ use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::normalize::needs_normalization;
 use crate::traits::{
-    BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, PredicateObligation,
-    Reveal, ScrubbedTraitError,
+    BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, Reveal, ScrubbedTraitError,
 };
 
 #[extension(pub trait QueryNormalizeExt<'tcx>)]
@@ -80,7 +80,9 @@ impl<'a, 'tcx> At<'a, 'tcx> {
             match crate::solve::deeply_normalize_with_skipped_universes::<_, ScrubbedTraitError<'tcx>>(
                 self, value, universes,
             ) {
-                Ok(value) => return Ok(Normalized { value, obligations: vec![] }),
+                Ok(value) => {
+                    return Ok(Normalized { value, obligations: PredicateObligations::new() });
+                }
                 Err(_errors) => {
                     return Err(NoSolution);
                 }
@@ -88,14 +90,14 @@ impl<'a, 'tcx> At<'a, 'tcx> {
         }
 
         if !needs_normalization(&value, self.param_env.reveal()) {
-            return Ok(Normalized { value, obligations: vec![] });
+            return Ok(Normalized { value, obligations: PredicateObligations::new() });
         }
 
         let mut normalizer = QueryNormalizer {
             infcx: self.infcx,
             cause: self.cause,
             param_env: self.param_env,
-            obligations: vec![],
+            obligations: PredicateObligations::new(),
             cache: SsoHashMap::new(),
             anon_depth: 0,
             universes,
@@ -164,7 +166,7 @@ struct QueryNormalizer<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
     cause: &'a ObligationCause<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    obligations: Vec<PredicateObligation<'tcx>>,
+    obligations: PredicateObligations<'tcx>,
     cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
     anon_depth: usize,
     universes: Vec<Option<ty::UniverseIndex>>,
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index a765de92afd..5ae8c87ec02 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -2,7 +2,7 @@ use std::fmt;
 
 use rustc_errors::ErrorGuaranteed;
 use rustc_infer::infer::canonical::Certainty;
-use rustc_infer::traits::PredicateObligation;
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
@@ -103,13 +103,13 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
         (
             Self::QueryResponse,
             Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
-            Vec<PredicateObligation<'tcx>>,
+            PredicateObligations<'tcx>,
             Certainty,
         ),
         NoSolution,
     > {
         if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
-            return Ok((result, None, vec![], Certainty::Proven));
+            return Ok((result, None, PredicateObligations::new(), Certainty::Proven));
         }
 
         let mut canonical_var_values = OriginalQueryValues::default();
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 20adda6f0de..52048ca79f9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -12,7 +12,9 @@ use hir::LangItem;
 use hir::def_id::DefId;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_hir as hir;
-use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation, SelectionError};
+use rustc_infer::traits::{
+    Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError,
+};
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
 use rustc_middle::{bug, span_bug};
@@ -963,7 +965,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 0,
                 // We're *intentionally* throwing these away,
                 // since we don't actually use them.
-                &mut vec![],
+                &mut PredicateObligations::new(),
             )
             .as_type()
             .unwrap();
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 5141e969608..cc5c7532b50 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -24,7 +24,7 @@ use rustc_span::def_id::DefId;
 use tracing::{debug, instrument};
 
 use super::SelectionCandidate::{self, *};
-use super::{BuiltinImplConditions, SelectionContext};
+use super::{BuiltinImplConditions, PredicateObligations, SelectionContext};
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::util::{self, closure_trait_ref_and_return_type};
 use crate::traits::{
@@ -85,7 +85,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             // No nested obligations or confirmation process. The checks that we do in
             // candidate assembly are sufficient.
-            AsyncFnKindHelperCandidate => ImplSource::Builtin(BuiltinImplSource::Misc, vec![]),
+            AsyncFnKindHelperCandidate => {
+                ImplSource::Builtin(BuiltinImplSource::Misc, PredicateObligations::new())
+            }
 
             CoroutineCandidate => {
                 let vtable_coroutine = self.confirm_coroutine_candidate(obligation)?;
@@ -121,7 +123,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // This indicates something like `Trait + Send: Send`. In this case, we know that
                 // this holds because that's what the object type is telling us, and there's really
                 // no additional obligations to prove and no types in particular to unify, etc.
-                ImplSource::Builtin(BuiltinImplSource::Misc, Vec::new())
+                ImplSource::Builtin(BuiltinImplSource::Misc, PredicateObligations::new())
             }
 
             BuiltinUnsizeCandidate => self.confirm_builtin_unsize_candidate(obligation)?,
@@ -149,7 +151,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         idx: usize,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let tcx = self.tcx();
 
         let placeholder_trait_predicate =
@@ -179,7 +181,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             HigherRankedType,
             candidate,
         );
-        let mut obligations = Vec::new();
+        let mut obligations = PredicateObligations::new();
         let candidate = normalize_with_depth_to(
             self,
             obligation.param_env,
@@ -226,7 +228,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         param: ty::PolyTraitRef<'tcx>,
-    ) -> Vec<PredicateObligation<'tcx>> {
+    ) -> PredicateObligations<'tcx> {
         debug!(?obligation, ?param, "confirm_param_candidate");
 
         // During evaluation, we already checked that this
@@ -249,7 +251,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         has_nested: bool,
-    ) -> Vec<PredicateObligation<'tcx>> {
+    ) -> PredicateObligations<'tcx> {
         debug!(?obligation, ?has_nested, "confirm_builtin_candidate");
 
         let tcx = self.tcx();
@@ -279,7 +281,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 nested,
             )
         } else {
-            vec![]
+            PredicateObligations::new()
         };
 
         debug!(?obligations);
@@ -291,7 +293,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_transmutability_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         use rustc_transmute::{Answer, Assume, Condition};
 
         /// Generate sub-obligations for reference-to-reference transmutations.
@@ -301,7 +303,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             (src_lifetime, src_ty, src_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
             (dst_lifetime, dst_ty, dst_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
             assume: Assume,
-        ) -> Vec<PredicateObligation<'tcx>> {
+        ) -> PredicateObligations<'tcx> {
             let make_transmute_obl = |src, dst| {
                 let transmute_trait = obligation.predicate.def_id();
                 let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2);
@@ -347,7 +349,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // Given a transmutation from `&'a (mut) Src` and `&'dst (mut) Dst`,
             // it is always the case that `Src` must be transmutable into `Dst`,
             // and that that `'src` must outlive `'dst`.
-            let mut obls = vec![make_transmute_obl(src_ty, dst_ty)];
+            let mut obls = PredicateObligations::with_capacity(1);
+            obls.push(make_transmute_obl(src_ty, dst_ty));
             if !assume.lifetimes {
                 obls.push(make_outlives_obl(src_lifetime, dst_lifetime));
             }
@@ -382,7 +385,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             obligation: &PolyTraitObligation<'tcx>,
             cond: Condition<rustc_transmute::layout::rustc::Ref<'tcx>>,
             assume: Assume,
-        ) -> Vec<PredicateObligation<'tcx>> {
+        ) -> PredicateObligations<'tcx> {
             match cond {
                 // FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll`
                 // Not possible until the trait solver supports disjunctions of obligations
@@ -424,7 +427,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let fully_flattened = match maybe_transmutable {
             Answer::No(_) => Err(Unimplemented)?,
             Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, cond, assume),
-            Answer::Yes => vec![],
+            Answer::Yes => PredicateObligations::new(),
         };
 
         debug!(?fully_flattened);
@@ -439,7 +442,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_auto_impl_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         debug!(?obligation, "confirm_auto_impl_candidate");
 
         let self_ty = obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
@@ -453,14 +456,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &PolyTraitObligation<'tcx>,
         trait_def_id: DefId,
         nested: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
-    ) -> Vec<PredicateObligation<'tcx>> {
+    ) -> PredicateObligations<'tcx> {
         debug!(?nested, "vtable_auto_impl");
         ensure_sufficient_stack(|| {
             let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
 
             let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
             let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref);
-            let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations(
+            let trait_obligations = self.impl_or_trait_obligations(
                 &cause,
                 obligation.recursion_depth + 1,
                 obligation.param_env,
@@ -566,7 +569,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         );
         let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty);
 
-        let mut nested = vec![];
+        let mut nested = PredicateObligations::new();
 
         let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref));
         let unnormalized_upcast_trait_ref =
@@ -706,7 +709,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         fn_host_effect: ty::Const<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         debug!(?obligation, "confirm_fn_pointer_candidate");
         let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
         let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
@@ -750,7 +753,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_trait_alias_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> Vec<PredicateObligation<'tcx>> {
+    ) -> PredicateObligations<'tcx> {
         debug!(?obligation, "confirm_trait_alias_candidate");
 
         let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
@@ -775,7 +778,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_coroutine_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
         let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
@@ -805,7 +808,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_future_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
         let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
@@ -835,7 +838,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_iterator_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
         let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
@@ -865,7 +868,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_async_iterator_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
         let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
         let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
@@ -896,7 +899,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_closure_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
         let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
 
@@ -926,13 +929,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_async_closure_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
         let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
 
         let tcx = self.tcx();
 
-        let mut nested = vec![];
+        let mut nested = PredicateObligations::new();
         let (trait_ref, kind_ty) = match *self_ty.kind() {
             ty::CoroutineClosure(_, args) => {
                 let args = args.as_coroutine_closure();
@@ -1055,7 +1058,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: TraitObligation<'tcx>,
         found_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
             HigherRankedType,
@@ -1210,7 +1213,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 //  words, if the object type is `Foo + Send`, this would create an obligation for
                 //  the `Send` check.)
                 //  - Projection predicates
-                let mut nested: Vec<_> = data
+                let mut nested: PredicateObligations<'_> = data
                     .iter()
                     .map(|predicate| predicate_to_obligation(predicate.with_self_ty(tcx, source)))
                     .collect();
@@ -1254,7 +1257,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let tail_field = def.non_enum_variant().tail();
                 let tail_field_ty = tcx.type_of(tail_field.did);
 
-                let mut nested = vec![];
+                let mut nested = PredicateObligations::new();
 
                 // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`,
                 // normalizing in the process, since `type_of` returns something directly from
@@ -1339,7 +1342,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         impl_def_id: Option<DefId>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         let Some(host_effect_index) =
             self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
         else {
@@ -1353,7 +1356,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let tcx = self.tcx();
         let self_ty = obligation.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
 
-        let mut nested = vec![];
+        let mut nested = PredicateObligations::new();
         let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
 
         // If we have a custom `impl const Drop`, then
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index fba1d1025ca..621babe9104 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -18,7 +18,7 @@ use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::relate::TypeRelation;
-use rustc_infer::traits::TraitObligation;
+use rustc_infer::traits::{PredicateObligations, TraitObligation};
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds};
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -1067,7 +1067,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 && fresh_trait_pred.has_aliases()
                 && fresh_trait_pred.is_global()
             {
-                let mut nested_obligations = Vec::new();
+                let mut nested_obligations = PredicateObligations::new();
                 let predicate = normalize_with_depth_to(
                     this,
                     param_env,
@@ -1715,7 +1715,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> ProjectionMatchesProjection {
         debug_assert_eq!(obligation.predicate.def_id, env_predicate.projection_def_id());
 
-        let mut nested_obligations = Vec::new();
+        let mut nested_obligations = PredicateObligations::new();
         let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
             BoundRegionConversionTime::HigherRankedType,
@@ -2410,7 +2410,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         recursion_depth: usize,
         trait_def_id: DefId,
         types: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
-    ) -> Vec<PredicateObligation<'tcx>> {
+    ) -> PredicateObligations<'tcx> {
         // Because the types were potentially derived from
         // higher-ranked obligations they may reference late-bound
         // regions. For example, `for<'a> Foo<&'a i32> : Copy` would
@@ -2552,9 +2552,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
         a_region: ty::Region<'tcx>,
         b_region: ty::Region<'tcx>,
-    ) -> SelectionResult<'tcx, Vec<PredicateObligation<'tcx>>> {
+    ) -> SelectionResult<'tcx, PredicateObligations<'tcx>> {
         let tcx = self.tcx();
-        let mut nested = vec![];
+        let mut nested = PredicateObligations::new();
 
         // We may upcast to auto traits that are either explicitly listed in
         // the object type's bounds, or implied by the principal trait ref's
@@ -2705,7 +2705,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
+    ) -> Result<PredicateObligations<'tcx>, ()> {
         self.match_poly_trait_ref(obligation, where_clause_trait_ref)
     }
 
@@ -2716,7 +2716,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
+    ) -> Result<PredicateObligations<'tcx>, ()> {
         let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
         let trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
@@ -2797,7 +2797,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         def_id: DefId,              // of impl or trait
         args: GenericArgsRef<'tcx>, // for impl or trait
         parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
-    ) -> Vec<PredicateObligation<'tcx>> {
+    ) -> PredicateObligations<'tcx> {
         let tcx = self.tcx();
 
         // To allow for one-pass evaluation of the nested obligation,
@@ -2817,7 +2817,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         let predicates = tcx.predicates_of(def_id);
         assert_eq!(predicates.parent, None);
         let predicates = predicates.instantiate_own(tcx, args);
-        let mut obligations = Vec::with_capacity(predicates.len());
+        let mut obligations = PredicateObligations::with_capacity(predicates.len());
         for (index, (predicate, span)) in predicates.into_iter().enumerate() {
             let cause = if tcx.is_lang_item(parent_trait_pred.def_id(), LangItem::CoerceUnsized) {
                 cause.clone()
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index a849cdfe125..07e68e5a3e8 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -2,7 +2,7 @@ use std::iter;
 
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
-use rustc_infer::traits::ObligationCauseCode;
+use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
 use rustc_middle::bug;
 use rustc_middle::ty::{
     self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable,
@@ -27,7 +27,7 @@ pub fn obligations<'tcx>(
     recursion_depth: usize,
     arg: GenericArg<'tcx>,
     span: Span,
-) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
+) -> Option<PredicateObligations<'tcx>> {
     // Handle the "livelock" case (see comment above) by bailing out if necessary.
     let arg = match arg.unpack() {
         GenericArgKind::Type(ty) => {
@@ -61,11 +61,18 @@ pub fn obligations<'tcx>(
             .into()
         }
         // There is nothing we have to do for lifetimes.
-        GenericArgKind::Lifetime(..) => return Some(Vec::new()),
+        GenericArgKind::Lifetime(..) => return Some(PredicateObligations::new()),
     };
 
-    let mut wf =
-        WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None };
+    let mut wf = WfPredicates {
+        infcx,
+        param_env,
+        body_id,
+        span,
+        out: PredicateObligations::new(),
+        recursion_depth,
+        item: None,
+    };
     wf.compute(arg);
     debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
 
@@ -82,7 +89,7 @@ pub fn unnormalized_obligations<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     arg: GenericArg<'tcx>,
-) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
+) -> Option<PredicateObligations<'tcx>> {
     debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
 
     // However, if `arg` IS an unresolved inference variable, returns `None`,
@@ -93,7 +100,7 @@ pub fn unnormalized_obligations<'tcx>(
     }
 
     if let ty::GenericArgKind::Lifetime(..) = arg.unpack() {
-        return Some(vec![]);
+        return Some(PredicateObligations::new());
     }
 
     let mut wf = WfPredicates {
@@ -101,7 +108,7 @@ pub fn unnormalized_obligations<'tcx>(
         param_env,
         body_id: CRATE_DEF_ID,
         span: DUMMY_SP,
-        out: vec![],
+        out: PredicateObligations::new(),
         recursion_depth: 0,
         item: None,
     };
@@ -120,13 +127,13 @@ pub fn trait_obligations<'tcx>(
     trait_pred: ty::TraitPredicate<'tcx>,
     span: Span,
     item: &'tcx hir::Item<'tcx>,
-) -> Vec<traits::PredicateObligation<'tcx>> {
+) -> PredicateObligations<'tcx> {
     let mut wf = WfPredicates {
         infcx,
         param_env,
         body_id,
         span,
-        out: vec![],
+        out: PredicateObligations::new(),
         recursion_depth: 0,
         item: Some(item),
     };
@@ -147,13 +154,13 @@ pub fn clause_obligations<'tcx>(
     body_id: LocalDefId,
     clause: ty::Clause<'tcx>,
     span: Span,
-) -> Vec<traits::PredicateObligation<'tcx>> {
+) -> PredicateObligations<'tcx> {
     let mut wf = WfPredicates {
         infcx,
         param_env,
         body_id,
         span,
-        out: vec![],
+        out: PredicateObligations::new(),
         recursion_depth: 0,
         item: None,
     };
@@ -192,7 +199,7 @@ struct WfPredicates<'a, 'tcx> {
     param_env: ty::ParamEnv<'tcx>,
     body_id: LocalDefId,
     span: Span,
-    out: Vec<traits::PredicateObligation<'tcx>>,
+    out: PredicateObligations<'tcx>,
     recursion_depth: usize,
     item: Option<&'tcx hir::Item<'tcx>>,
 }
@@ -323,7 +330,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         traits::ObligationCause::new(self.span, self.body_id, code)
     }
 
-    fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
+    fn normalize(self, infcx: &InferCtxt<'tcx>) -> PredicateObligations<'tcx> {
         // Do not normalize `wf` obligations with the new solver.
         //
         // The current deep normalization routine with the new solver does not
@@ -336,7 +343,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
         let cause = self.cause(ObligationCauseCode::WellFormed(None));
         let param_env = self.param_env;
-        let mut obligations = Vec::with_capacity(self.out.len());
+        let mut obligations = PredicateObligations::with_capacity(self.out.len());
         for mut obligation in self.out {
             assert!(!obligation.has_escaping_bound_vars());
             let mut selcx = traits::SelectionContext::new(infcx);
@@ -553,7 +560,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         &mut self,
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
-    ) -> Vec<traits::PredicateObligation<'tcx>> {
+    ) -> PredicateObligations<'tcx> {
         let predicates = self.tcx().predicates_of(def_id);
         let mut origins = vec![def_id; predicates.predicates.len()];
         let mut head = predicates;
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index 3102da218db..4c2b7e4769a 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -1,5 +1,6 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -30,7 +31,7 @@ fn normalize_canonicalized_projection_ty<'tcx>(
             debug_assert!(!ocx.infcx.next_trait_solver());
             let selcx = &mut SelectionContext::new(ocx.infcx);
             let cause = ObligationCause::dummy();
-            let mut obligations = vec![];
+            let mut obligations = PredicateObligations::new();
             let answer =
                 traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations);
             ocx.register_obligations(obligations);
@@ -99,7 +100,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>(
         |ocx, ParamEnvAnd { param_env, value: goal }| {
             let selcx = &mut SelectionContext::new(ocx.infcx);
             let cause = ObligationCause::dummy();
-            let mut obligations = vec![];
+            let mut obligations = PredicateObligations::new();
             let answer = traits::normalize_inherent_projection(
                 selcx,
                 param_env,