diff options
Diffstat (limited to 'src/librustc')
| -rw-r--r-- | src/librustc/infer/mod.rs | 44 | ||||
| -rw-r--r-- | src/librustc/traits/fulfill.rs | 17 |
2 files changed, 49 insertions, 12 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a886c44a479..c5712cc9941 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1562,11 +1562,7 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { ShallowResolver { infcx } } - // We have this force-inlined variant of `shallow_resolve` for the one - // callsite that is extremely hot. All other callsites use the normal - // variant. - #[inline(always)] - pub fn inlined_shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { + pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { match typ.sty { ty::Infer(ty::TyVar(v)) => { // Not entirely obvious: if `typ` is a type variable, @@ -1601,6 +1597,42 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { _ => typ, } } + + // `resolver.shallow_resolve_changed(ty)` is equivalent to + // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always + // inlined, despite being large, because it has a single call site that is + // extremely hot. + #[inline(always)] + pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool { + match typ.sty { + ty::Infer(ty::TyVar(v)) => { + use self::type_variable::TypeVariableValue; + + // See the comment in `shallow_resolve()`. + match self.infcx.type_variables.borrow_mut().probe(v) { + TypeVariableValue::Known { value: t } => self.fold_ty(t) != typ, + TypeVariableValue::Unknown { .. } => false, + } + } + + ty::Infer(ty::IntVar(v)) => { + match self.infcx.int_unification_table.borrow_mut().probe_value(v) { + Some(v) => v.to_type(self.infcx.tcx) != typ, + None => false, + } + } + + ty::Infer(ty::FloatVar(v)) => { + match self.infcx.float_unification_table.borrow_mut().probe_value(v) { + Some(v) => v.to_type(self.infcx.tcx) != typ, + None => false, + } + } + + _ => false, + } + } + } impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { @@ -1609,7 +1641,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.inlined_shallow_resolve(ty) + self.shallow_resolve(ty) } fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 4494c034d51..805727b6ce0 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -256,15 +256,20 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { &mut self, pending_obligation: &mut Self::Obligation, ) -> ProcessResult<Self::Obligation, Self::Error> { - // if we were stalled on some unresolved variables, first check + // If we were stalled on some unresolved variables, first check // whether any of them have been resolved; if not, don't bother // doing more work yet if !pending_obligation.stalled_on.is_empty() { - if pending_obligation.stalled_on.iter().all(|&ty| { - // Use the force-inlined variant of shallow_resolve() because this code is hot. - let resolved = ShallowResolver::new(self.selcx.infcx()).inlined_shallow_resolve(ty); - resolved == ty // nothing changed here - }) { + let mut changed = false; + // 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) { + changed = true; + break; + } + } + if !changed { debug!("process_predicate: pending obligation {:?} still stalled on {:?}", self.selcx.infcx() .resolve_vars_if_possible(&pending_obligation.obligation), |
