diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 18a3775954317..076b44948467d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -253,7 +253,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); let lang_items = self.tcx().lang_items(); - let obligations = if has_nested { + let mut obligations = vec![]; + if has_nested { let trait_def = obligation.predicate.def_id(); let conditions = if Some(trait_def) == lang_items.sized_trait() { self.sized_conditions(obligation) @@ -276,10 +277,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, trait_def, nested, + &mut obligations, ) }) - } else { - vec![] }; debug!(?obligations); @@ -315,32 +315,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ensure_sufficient_stack(|| { let cause = obligation.derived_cause(BuiltinDerivedObligation); - let trait_obligations: Vec> = - self.infcx.commit_unconditionally(|_| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref); - self.impl_or_trait_obligations( - &cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - &trait_ref.substs, - obligation.predicate, - ) - }); + let mut obligations = vec![]; + self.infcx.commit_unconditionally(|_| { + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref); + // Adds the predicates from the trait. Note that this contains a `Self: Trait` + // predicate as usual. It will have no effect because auto traits are coinductive. + self.impl_or_trait_obligations( + &cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + &trait_ref.substs, + obligation.predicate, + &mut obligations, + ) + }); - let mut obligations = self.collect_predicates_for_types( + self.collect_predicates_for_types( obligation.param_env, cause, obligation.recursion_depth + 1, trait_def_id, nested, + &mut obligations, ); - // Adds the predicates from the trait. Note that this contains a `Self: Trait` - // predicate as usual. It won't have any effect since auto traits are coinductive. - obligations.extend(trait_obligations); - debug!(?obligations, "vtable_auto_impl"); ImplSourceAutoImplData { trait_def_id, nested: obligations } @@ -383,13 +383,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl"); - let mut impl_obligations = self.impl_or_trait_obligations( + let mut impl_obligations = vec![]; + self.impl_or_trait_obligations( cause, recursion_depth, param_env, impl_def_id, &substs.value, parent_trait_pred, + &mut impl_obligations, ); debug!(?impl_obligations, "vtable_impl"); @@ -623,13 +625,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_def_id = trait_ref.def_id; let substs = trait_ref.substs; - let trait_obligations = self.impl_or_trait_obligations( + let mut trait_obligations = vec![]; + self.impl_or_trait_obligations( &obligation.cause, obligation.recursion_depth, obligation.param_env, trait_def_id, &substs, obligation.predicate, + &mut trait_obligations, ); debug!(?trait_def_id, ?trait_obligations, "trait alias obligations"); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e69bf6eca90ef..385ec760e7430 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -41,6 +41,7 @@ use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::sym; +use smallvec::SmallVec; use std::cell::{Cell, RefCell}; use std::cmp; @@ -1360,7 +1361,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_projection_obligation_against_definition_bounds( &mut self, obligation: &TraitObligation<'tcx>, - ) -> smallvec::SmallVec<[usize; 2]> { + ) -> SmallVec<[usize; 2]> { let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate); @@ -2016,7 +2017,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth: usize, trait_def_id: DefId, types: ty::Binder<'tcx, Vec>>, - ) -> Vec> { + out: &mut Vec>, + ) { // 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 @@ -2030,17 +2032,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `for<'a> &'a i32` becomes `&0 i32`. // 2. Produce something like `&'0 i32 : Copy` // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy` - + // + // This function is called enough that it's better to append to a `&mut + // Vec` than return a `Vec`, to avoid allocations. types .as_ref() .skip_binder() // binder moved -\ .iter() - .flat_map(|ty| { + .for_each(|ty| { let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/ self.infcx.commit_unconditionally(|_| { let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); - let Normalized { value: normalized_ty, mut obligations } = + // `obligations` is almost always empty. + let Normalized { value: normalized_ty, obligations } = ensure_sufficient_stack(|| { project::normalize_with_depth( self, @@ -2050,6 +2055,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { placeholder_ty, ) }); + out.extend(obligations); let placeholder_obligation = predicate_for_trait_def( self.tcx(), param_env, @@ -2059,11 +2065,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { normalized_ty, &[], ); - obligations.push(placeholder_obligation); - obligations + out.push(placeholder_obligation); }) - }) - .collect() + }); } /////////////////////////////////////////////////////////////////////////// @@ -2337,7 +2341,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { def_id: DefId, // of impl or trait substs: SubstsRef<'tcx>, // for impl or trait parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, - ) -> Vec> { + out: &mut Vec>, + ) { let tcx = self.tcx(); // To allow for one-pass evaluation of the nested obligation, @@ -2357,7 +2362,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicates = tcx.predicates_of(def_id); debug!(?predicates); assert_eq!(predicates.parent, None); - let mut obligations = Vec::with_capacity(predicates.predicates.len()); + out.reserve(predicates.predicates.len()); let parent_code = cause.clone_code(); for (predicate, span) in predicates.predicates { let span = *span; @@ -2375,12 +2380,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause.clone(), recursion_depth, predicate.subst(tcx, substs), - &mut obligations, + out, ); - obligations.push(Obligation { cause, recursion_depth, param_env, predicate }); + out.push(Obligation { cause, recursion_depth, param_env, predicate }); } - - obligations } }