Auto merge of #80454 - JulianKnodt:ob_forest_op, r=matthewjasper

Skip Ty w/o infer ty/const in trait select

Remove some allocations & also add `skip_current_subtree` to skip subtrees with no inferred items.

r? `@eddyb` since marked in the FIXME
This commit is contained in:
bors 2021-02-27 17:35:35 +00:00
commit 94736c434e
2 changed files with 25 additions and 20 deletions

View File

@ -13,7 +13,7 @@ type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
pub struct TypeWalker<'tcx> { pub struct TypeWalker<'tcx> {
stack: TypeWalkerStack<'tcx>, stack: TypeWalkerStack<'tcx>,
last_subtree: usize, last_subtree: usize,
visited: SsoHashSet<GenericArg<'tcx>>, pub visited: SsoHashSet<GenericArg<'tcx>>,
} }
/// An iterator for walking the type tree. /// An iterator for walking the type tree.

View File

@ -499,10 +499,10 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
) { ) {
Ok(()) => ProcessResult::Changed(vec![]), Ok(()) => ProcessResult::Changed(vec![]),
Err(ErrorHandled::TooGeneric) => { Err(ErrorHandled::TooGeneric) => {
pending_obligation.stalled_on = substs pending_obligation.stalled_on.clear();
.iter() pending_obligation.stalled_on.extend(
.filter_map(TyOrConstInferVar::maybe_from_generic_arg) substs.iter().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
.collect(); );
ProcessResult::Unchanged ProcessResult::Unchanged
} }
Err(e) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))), Err(e) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))),
@ -544,13 +544,10 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
) { ) {
Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)), Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)),
Err(ErrorHandled::TooGeneric) => { Err(ErrorHandled::TooGeneric) => {
stalled_on.append( stalled_on.extend(
&mut substs substs
.iter() .iter()
.filter_map(|arg| { .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
TyOrConstInferVar::maybe_from_generic_arg(arg)
})
.collect(),
); );
Err(ErrorHandled::TooGeneric) Err(ErrorHandled::TooGeneric)
} }
@ -634,10 +631,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
// only reason we can fail to make progress on // only reason we can fail to make progress on
// trait selection is because we don't have enough // trait selection is because we don't have enough
// information about the types in the trait. // information about the types in the trait.
*stalled_on = substs_infer_vars( stalled_on.clear();
stalled_on.extend(substs_infer_vars(
self.selcx, self.selcx,
trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs), trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
); ));
debug!( debug!(
"process_predicate: pending obligation {:?} now stalled on {:?}", "process_predicate: pending obligation {:?} now stalled on {:?}",
@ -664,10 +662,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
match project::poly_project_and_unify_type(self.selcx, &project_obligation) { match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)), Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
Ok(Ok(None)) => { Ok(Ok(None)) => {
*stalled_on = substs_infer_vars( stalled_on.clear();
stalled_on.extend(substs_infer_vars(
self.selcx, self.selcx,
project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs), project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
); ));
ProcessResult::Unchanged ProcessResult::Unchanged
} }
// Let the caller handle the recursion // Let the caller handle the recursion
@ -683,18 +682,24 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
fn substs_infer_vars<'a, 'tcx>( fn substs_infer_vars<'a, 'tcx>(
selcx: &mut SelectionContext<'a, 'tcx>, selcx: &mut SelectionContext<'a, 'tcx>,
substs: ty::Binder<SubstsRef<'tcx>>, substs: ty::Binder<SubstsRef<'tcx>>,
) -> Vec<TyOrConstInferVar<'tcx>> { ) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
selcx selcx
.infcx() .infcx()
.resolve_vars_if_possible(substs) .resolve_vars_if_possible(substs)
.skip_binder() // ok because this check doesn't care about regions .skip_binder() // ok because this check doesn't care about regions
.iter() .iter()
// FIXME(eddyb) try using `skip_current_subtree` to skip everything that
// doesn't contain inference variables, not just the outermost level.
.filter(|arg| arg.has_infer_types_or_consts()) .filter(|arg| arg.has_infer_types_or_consts())
.flat_map(|arg| arg.walk()) .flat_map(|arg| {
let mut walker = arg.walk();
while let Some(c) = walker.next() {
if !c.has_infer_types_or_consts() {
walker.visited.remove(&c);
walker.skip_current_subtree();
}
}
walker.visited.into_iter()
})
.filter_map(TyOrConstInferVar::maybe_from_generic_arg) .filter_map(TyOrConstInferVar::maybe_from_generic_arg)
.collect()
} }
fn to_fulfillment_error<'tcx>( fn to_fulfillment_error<'tcx>(