From 21f35bc26f1ffccf30916b7d6930d1526172f2da Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 6 Dec 2019 16:57:57 +1100 Subject: [PATCH] Change `PendingPredicateObligation::stalled_on`'s type. From a `Vec` to a `Vec`, because that's a more restrictive type. This is a perf win because the ultra-hot function `shallow_resolve_changed` has less pattern-matching to do. --- src/librustc/infer/mod.rs | 16 +++++++--------- src/librustc/traits/fulfill.rs | 30 +++++++++++++++++++----------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index fca7704d5ee..73977878af3 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1617,30 +1617,28 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always // inlined, despite being large, because it has only two call sites that // are extremely hot. - // - // Note that `typ` is always a `ty::Infer(_)`. #[inline(always)] - pub fn shallow_resolve_changed(&self, typ: Ty<'tcx>) -> bool { - match typ.kind { - ty::Infer(ty::TyVar(v)) => { + pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool { + match infer { + ty::TyVar(v) => { use self::type_variable::TypeVariableValue; - // If `inlined_probe` returns a `Known` value it never matches - // `typ`. + // If `inlined_probe` returns a `Known` value its `kind` never + // matches `infer`. match self.infcx.type_variables.borrow_mut().inlined_probe(v) { TypeVariableValue::Unknown { .. } => false, TypeVariableValue::Known { .. } => true, } } - ty::Infer(ty::IntVar(v)) => { + ty::IntVar(v) => { // If inlined_probe_value returns a value it's always a // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a // `ty::Infer(_)`. self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v).is_some() } - ty::Infer(ty::FloatVar(v)) => { + ty::FloatVar(v) => { // If inlined_probe_value returns a value it's always a // `ty::Float(_)`, which nevers matches a `ty::Infer(_)`. // diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index a981162fdc3..27731990d2b 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -65,7 +65,7 @@ pub struct FulfillmentContext<'tcx> { #[derive(Clone, Debug)] pub struct PendingPredicateObligation<'tcx> { pub obligation: PredicateObligation<'tcx>, - pub stalled_on: Vec>, + pub stalled_on: Vec, } // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -263,8 +263,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { // Match arms are in order of frequency, which matters because this // code is so hot. 1 and 0 dominate; 2+ is fairly rare. 1 => { - let ty = pending_obligation.stalled_on[0]; - ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) + let infer = pending_obligation.stalled_on[0]; + ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) } 0 => { // In this case we haven't changed, but wish to make a change. @@ -274,8 +274,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { // This `for` loop was once a call to `all()`, but this lower-level // form was a perf win. See #64545 for details. (|| { - for &ty in &pending_obligation.stalled_on { - if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) { + for &infer in &pending_obligation.stalled_on { + if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) { return true; } } @@ -305,6 +305,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); + fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy { + match ty.kind { + ty::Infer(infer) => infer, + _ => panic!(), + } + } + match obligation.predicate { ty::Predicate::Trait(ref data) => { let trait_obligation = obligation.with(data.clone()); @@ -459,7 +466,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { obligation.cause.span, ) { None => { - pending_obligation.stalled_on = vec![ty]; + pending_obligation.stalled_on = vec![infer_ty(ty)]; ProcessResult::Unchanged } Some(os) => ProcessResult::Changed(mk_pending(os)) @@ -472,8 +479,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { subtype) { None => { // None means that both are unresolved. - pending_obligation.stalled_on = vec![subtype.skip_binder().a, - subtype.skip_binder().b]; + pending_obligation.stalled_on = vec![infer_ty(subtype.skip_binder().a), + infer_ty(subtype.skip_binder().b)]; ProcessResult::Unchanged } Some(Ok(ok)) => { @@ -517,7 +524,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { )) } } else { - pending_obligation.stalled_on = substs.types().collect(); + pending_obligation.stalled_on = + substs.types().map(|ty| infer_ty(ty)).collect(); ProcessResult::Unchanged } } @@ -542,13 +550,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { fn trait_ref_type_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, t: ty::PolyTraitRef<'tcx>, -) -> Vec> { +) -> Vec { t.skip_binder() // ok b/c this check doesn't care about regions .input_types() .map(|t| selcx.infcx().resolve_vars_if_possible(&t)) .filter(|t| t.has_infer_types()) .flat_map(|t| t.walk()) - .filter(|t| match t.kind { ty::Infer(_) => true, _ => false }) + .filter_map(|t| match t.kind { ty::Infer(infer) => Some(infer), _ => None }) .collect() }