Skip to content

Commit 528b6a4

Browse files
committed
Optimize obligation gathering.
By passing in a `&mut Vec` in various places and appending to it, rather than building many tiny `Vec`'s and then combining them. This removes about 20% of the allocations occurred in a `check` build of a test program from #87012, making it roughly 2% faster.
1 parent 6a9080b commit 528b6a4

File tree

2 files changed

+45
-38
lines changed

2 files changed

+45
-38
lines changed

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+27-23
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
253253
debug!(?obligation, ?has_nested, "confirm_builtin_candidate");
254254

255255
let lang_items = self.tcx().lang_items();
256-
let obligations = if has_nested {
256+
let mut obligations = vec![];
257+
if has_nested {
257258
let trait_def = obligation.predicate.def_id();
258259
let conditions = if Some(trait_def) == lang_items.sized_trait() {
259260
self.sized_conditions(obligation)
@@ -276,10 +277,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
276277
obligation.recursion_depth + 1,
277278
trait_def,
278279
nested,
280+
&mut obligations,
279281
)
280282
})
281-
} else {
282-
vec![]
283283
};
284284

285285
debug!(?obligations);
@@ -315,32 +315,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
315315
ensure_sufficient_stack(|| {
316316
let cause = obligation.derived_cause(BuiltinDerivedObligation);
317317

318-
let trait_obligations: Vec<PredicateObligation<'_>> =
319-
self.infcx.commit_unconditionally(|_| {
320-
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
321-
let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
322-
self.impl_or_trait_obligations(
323-
&cause,
324-
obligation.recursion_depth + 1,
325-
obligation.param_env,
326-
trait_def_id,
327-
&trait_ref.substs,
328-
obligation.predicate,
329-
)
330-
});
318+
let mut obligations = vec![];
319+
self.infcx.commit_unconditionally(|_| {
320+
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
321+
let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
322+
// Adds the predicates from the trait. Note that this contains a `Self: Trait`
323+
// predicate as usual. It will have no effect because auto traits are coinductive.
324+
self.impl_or_trait_obligations(
325+
&cause,
326+
obligation.recursion_depth + 1,
327+
obligation.param_env,
328+
trait_def_id,
329+
&trait_ref.substs,
330+
obligation.predicate,
331+
&mut obligations,
332+
)
333+
});
331334

332-
let mut obligations = self.collect_predicates_for_types(
335+
self.collect_predicates_for_types(
333336
obligation.param_env,
334337
cause,
335338
obligation.recursion_depth + 1,
336339
trait_def_id,
337340
nested,
341+
&mut obligations,
338342
);
339343

340-
// Adds the predicates from the trait. Note that this contains a `Self: Trait`
341-
// predicate as usual. It won't have any effect since auto traits are coinductive.
342-
obligations.extend(trait_obligations);
343-
344344
debug!(?obligations, "vtable_auto_impl");
345345

346346
ImplSourceAutoImplData { trait_def_id, nested: obligations }
@@ -383,13 +383,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
383383
) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
384384
debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl");
385385

386-
let mut impl_obligations = self.impl_or_trait_obligations(
386+
let mut impl_obligations = vec![];
387+
self.impl_or_trait_obligations(
387388
cause,
388389
recursion_depth,
389390
param_env,
390391
impl_def_id,
391392
&substs.value,
392393
parent_trait_pred,
394+
&mut impl_obligations,
393395
);
394396

395397
debug!(?impl_obligations, "vtable_impl");
@@ -623,13 +625,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
623625
let trait_def_id = trait_ref.def_id;
624626
let substs = trait_ref.substs;
625627

626-
let trait_obligations = self.impl_or_trait_obligations(
628+
let mut trait_obligations = vec![];
629+
self.impl_or_trait_obligations(
627630
&obligation.cause,
628631
obligation.recursion_depth,
629632
obligation.param_env,
630633
trait_def_id,
631634
&substs,
632635
obligation.predicate,
636+
&mut trait_obligations,
633637
);
634638

635639
debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");

compiler/rustc_trait_selection/src/traits/select/mod.rs

+18-15
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
4141
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
4242
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
4343
use rustc_span::symbol::sym;
44+
use smallvec::SmallVec;
4445

4546
use std::cell::{Cell, RefCell};
4647
use std::cmp;
@@ -1360,7 +1361,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13601361
fn match_projection_obligation_against_definition_bounds(
13611362
&mut self,
13621363
obligation: &TraitObligation<'tcx>,
1363-
) -> smallvec::SmallVec<[usize; 2]> {
1364+
) -> SmallVec<[usize; 2]> {
13641365
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
13651366
let placeholder_trait_predicate =
13661367
self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
@@ -2016,7 +2017,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20162017
recursion_depth: usize,
20172018
trait_def_id: DefId,
20182019
types: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
2019-
) -> Vec<PredicateObligation<'tcx>> {
2020+
out: &mut Vec<PredicateObligation<'tcx>>,
2021+
) {
20202022
// Because the types were potentially derived from
20212023
// higher-ranked obligations they may reference late-bound
20222024
// regions. For example, `for<'a> Foo<&'a i32> : Copy` would
@@ -2030,17 +2032,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20302032
// `for<'a> &'a i32` becomes `&0 i32`.
20312033
// 2. Produce something like `&'0 i32 : Copy`
20322034
// 3. Re-bind the regions back to `for<'a> &'a i32 : Copy`
2033-
2035+
//
2036+
// This function is called enough that it's better to append to a `&mut
2037+
// Vec` than return a `Vec`, to avoid allocations.
20342038
types
20352039
.as_ref()
20362040
.skip_binder() // binder moved -\
20372041
.iter()
2038-
.flat_map(|ty| {
2042+
.for_each(|ty| {
20392043
let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/
20402044

20412045
self.infcx.commit_unconditionally(|_| {
20422046
let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
2043-
let Normalized { value: normalized_ty, mut obligations } =
2047+
// `obligations` is almost always empty.
2048+
let Normalized { value: normalized_ty, obligations } =
20442049
ensure_sufficient_stack(|| {
20452050
project::normalize_with_depth(
20462051
self,
@@ -2050,6 +2055,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20502055
placeholder_ty,
20512056
)
20522057
});
2058+
out.extend(obligations);
20532059
let placeholder_obligation = predicate_for_trait_def(
20542060
self.tcx(),
20552061
param_env,
@@ -2059,11 +2065,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20592065
normalized_ty,
20602066
&[],
20612067
);
2062-
obligations.push(placeholder_obligation);
2063-
obligations
2068+
out.push(placeholder_obligation);
20642069
})
2065-
})
2066-
.collect()
2070+
});
20672071
}
20682072

20692073
///////////////////////////////////////////////////////////////////////////
@@ -2337,7 +2341,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
23372341
def_id: DefId, // of impl or trait
23382342
substs: SubstsRef<'tcx>, // for impl or trait
23392343
parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
2340-
) -> Vec<PredicateObligation<'tcx>> {
2344+
out: &mut Vec<PredicateObligation<'tcx>>,
2345+
) {
23412346
let tcx = self.tcx();
23422347

23432348
// To allow for one-pass evaluation of the nested obligation,
@@ -2357,7 +2362,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
23572362
let predicates = tcx.predicates_of(def_id);
23582363
debug!(?predicates);
23592364
assert_eq!(predicates.parent, None);
2360-
let mut obligations = Vec::with_capacity(predicates.predicates.len());
2365+
out.reserve(predicates.predicates.len());
23612366
let parent_code = cause.clone_code();
23622367
for (predicate, span) in predicates.predicates {
23632368
let span = *span;
@@ -2375,12 +2380,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
23752380
cause.clone(),
23762381
recursion_depth,
23772382
predicate.subst(tcx, substs),
2378-
&mut obligations,
2383+
out,
23792384
);
2380-
obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
2385+
out.push(Obligation { cause, recursion_depth, param_env, predicate });
23812386
}
2382-
2383-
obligations
23842387
}
23852388
}
23862389

0 commit comments

Comments
 (0)