Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize obligation gathering. #92017

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 27 additions & 23 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -276,10 +277,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.recursion_depth + 1,
trait_def,
nested,
&mut obligations,
)
})
} else {
vec![]
};

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

let trait_obligations: Vec<PredicateObligation<'_>> =
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 }
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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");
Expand Down
33 changes: 18 additions & 15 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -2016,7 +2017,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
recursion_depth: usize,
trait_def_id: DefId,
types: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
) -> Vec<PredicateObligation<'tcx>> {
out: &mut Vec<PredicateObligation<'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
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -2059,11 +2065,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
normalized_ty,
&[],
);
obligations.push(placeholder_obligation);
obligations
out.push(placeholder_obligation);
})
})
.collect()
});
}

///////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -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<PredicateObligation<'tcx>> {
out: &mut Vec<PredicateObligation<'tcx>>,
) {
let tcx = self.tcx();

// To allow for one-pass evaluation of the nested obligation,
Expand All @@ -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;
Expand All @@ -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
}
}

Expand Down