// `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.
+ // inlined, despite being large, because it has only two call sites that
+ // are extremely hot.
#[inline(always)]
pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool {
match typ.sty {
&mut self,
pending_obligation: &mut Self::Obligation,
) -> ProcessResult<Self::Obligation, Self::Error> {
- // 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() {
- 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 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.
+ let change = match pending_obligation.stalled_on.len() {
+ // 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)
+ }
+ 0 => {
+ // In this case we haven't changed, but wish to make a change.
+ true
}
- if !changed {
- debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
- self.selcx.infcx()
- .resolve_vars_if_possible(&pending_obligation.obligation),
- pending_obligation.stalled_on);
- return ProcessResult::Unchanged;
+ _ => {
+ // 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) {
+ return true;
+ }
+ }
+ false
+ })()
}
- pending_obligation.stalled_on = vec![];
+ };
+
+ if !change {
+ debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
+ self.selcx.infcx()
+ .resolve_vars_if_possible(&pending_obligation.obligation),
+ pending_obligation.stalled_on);
+ return ProcessResult::Unchanged;
}
+ // This part of the code is much colder.
+
+ pending_obligation.stalled_on.truncate(0);
+
let obligation = &mut pending_obligation.obligation;
if obligation.predicate.has_infer_types() {