@@ -97,7 +97,17 @@ pub trait ObligationProcessor {
9797 type Error : Debug ;
9898 type OUT : OutcomeTrait < Obligation = Self :: Obligation , Error = Error < Self :: Obligation , Self :: Error > > ;
9999
100- fn needs_process_obligation ( & self , obligation : & Self :: Obligation ) -> bool ;
100+ /// Implementations can provide a fast-path to obligation-processing
101+ /// by counting the prefix of the passed iterator for which
102+ /// `needs_process_obligation` would return false.
103+ fn skippable_obligations < ' a > (
104+ & ' a self ,
105+ _it : impl Iterator < Item = & ' a Self :: Obligation > ,
106+ ) -> usize {
107+ 0
108+ }
109+
110+ fn needs_process_obligation ( & self , _obligation : & Self :: Obligation ) -> bool ;
101111
102112 fn process_obligation (
103113 & mut self ,
@@ -416,6 +426,10 @@ impl<O: ForestObligation> ObligationForest<O> {
416426 loop {
417427 let mut has_changed = false ;
418428
429+ // This is the super fast path for cheap-to-check conditions.
430+ let mut index =
431+ processor. skippable_obligations ( self . nodes . iter ( ) . map ( |n| & n. obligation ) ) ;
432+
419433 // Note that the loop body can append new nodes, and those new nodes
420434 // will then be processed by subsequent iterations of the loop.
421435 //
@@ -424,9 +438,8 @@ impl<O: ForestObligation> ObligationForest<O> {
424438 // `for index in 0..self.nodes.len() { ... }` because the range would
425439 // be computed with the initial length, and we would miss the appended
426440 // nodes. Therefore we use a `while` loop.
427- let mut index = 0 ;
428441 while let Some ( node) = self . nodes . get_mut ( index) {
429- // This test is extremely hot .
442+ // This is the moderately fast path when the prefix skipping above didn't work out .
430443 if node. state . get ( ) != NodeState :: Pending
431444 || !processor. needs_process_obligation ( & node. obligation )
432445 {
0 commit comments