Use iterators in `error_at` and `process_cycle`.

This makes the code a little faster, presumably because bounds checks
aren't needed on `nodes` accesses. It requires making `scratch` a
`RefCell`, which is not unreasonable.
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 9dbae95..0fa1f70 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -76,7 +76,7 @@
 use crate::indexed_vec::Idx;
 use crate::newtype_index;
 
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
 use std::hash;
@@ -156,7 +156,9 @@
     /// comments in `process_obligation` for details.
     waiting_cache: FxHashMap<O::Predicate, NodeIndex>,
 
-    scratch: Option<Vec<usize>>,
+    /// A scratch vector reused in various operations, to avoid allocating new
+    /// vectors.
+    scratch: RefCell<Vec<usize>>,
 
     obligation_tree_id_generator: ObligationTreeIdGenerator,
 
@@ -265,7 +267,7 @@
             nodes: vec![],
             done_cache: Default::default(),
             waiting_cache: Default::default(),
-            scratch: Some(vec![]),
+            scratch: RefCell::new(vec![]),
             obligation_tree_id_generator: (0..).map(ObligationTreeId),
             error_cache: Default::default(),
         }
@@ -345,8 +347,8 @@
     /// Converts all remaining obligations to the given error.
     pub fn to_errors<E: Clone>(&mut self, error: E) -> Vec<Error<O, E>> {
         let mut errors = vec![];
-        for i in 0..self.nodes.len() {
-            if let NodeState::Pending = self.nodes[i].state.get() {
+        for (i, node) in self.nodes.iter().enumerate() {
+            if let NodeState::Pending = node.state.get() {
                 let backtrace = self.error_at(i);
                 errors.push(Error {
                     error: error.clone(),
@@ -469,20 +471,20 @@
     /// report all cycles between them. This should be called
     /// after `mark_as_waiting` marks all nodes with pending
     /// subobligations as NodeState::Waiting.
-    fn process_cycles<P>(&mut self, processor: &mut P)
+    fn process_cycles<P>(&self, processor: &mut P)
         where P: ObligationProcessor<Obligation=O>
     {
-        let mut stack = self.scratch.take().unwrap();
+        let mut stack = self.scratch.replace(vec![]);
         debug_assert!(stack.is_empty());
 
         debug!("process_cycles()");
 
-        for i in 0..self.nodes.len() {
+        for (i, node) in self.nodes.iter().enumerate() {
             // For rustc-benchmarks/inflate-0.1.0 this state test is extremely
             // hot and the state is almost always `Pending` or `Waiting`. It's
             // a win to handle the no-op cases immediately to avoid the cost of
             // the function call.
-            match self.nodes[i].state.get() {
+            match node.state.get() {
                 NodeState::Waiting | NodeState::Pending | NodeState::Done | NodeState::Error => {},
                 _ => self.find_cycles_from_node(&mut stack, processor, i),
             }
@@ -491,7 +493,7 @@
         debug!("process_cycles: complete");
 
         debug_assert!(stack.is_empty());
-        self.scratch = Some(stack);
+        self.scratch.replace(stack);
     }
 
     fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, i: usize)
@@ -525,8 +527,8 @@
 
     /// Returns a vector of obligations for `p` and all of its
     /// ancestors, putting them into the error state in the process.
-    fn error_at(&mut self, mut i: usize) -> Vec<O> {
-        let mut error_stack = self.scratch.take().unwrap();
+    fn error_at(&self, mut i: usize) -> Vec<O> {
+        let mut error_stack = self.scratch.replace(vec![]);
         let mut trace = vec![];
 
         loop {
@@ -554,7 +556,7 @@
             );
         }
 
-        self.scratch = Some(error_stack);
+        self.scratch.replace(error_stack);
         trace
     }
 
@@ -608,7 +610,7 @@
     #[inline(never)]
     fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
         let nodes_len = self.nodes.len();
-        let mut node_rewrites: Vec<_> = self.scratch.take().unwrap();
+        let mut node_rewrites: Vec<_> = self.scratch.replace(vec![]);
         node_rewrites.extend(0..nodes_len);
         let mut dead_nodes = 0;
 
@@ -658,7 +660,7 @@
         // No compression needed.
         if dead_nodes == 0 {
             node_rewrites.truncate(0);
-            self.scratch = Some(node_rewrites);
+            self.scratch.replace(node_rewrites);
             return if do_completed == DoCompleted::Yes { Some(vec![]) } else { None };
         }
 
@@ -682,7 +684,7 @@
         self.apply_rewrites(&node_rewrites);
 
         node_rewrites.truncate(0);
-        self.scratch = Some(node_rewrites);
+        self.scratch.replace(node_rewrites);
 
         successful
     }