@@ -43,6 +43,7 @@ use middle::lang_items;
4343use rustc_data_structures:: bitvec:: BitVector ;
4444use rustc_data_structures:: snapshot_vec:: { SnapshotVecDelegate , SnapshotVec } ;
4545use std:: cell:: RefCell ;
46+ use std:: cmp;
4647use std:: fmt;
4748use std:: marker:: PhantomData ;
4849use std:: mem;
@@ -271,17 +272,101 @@ enum BuiltinImplConditions<'tcx> {
271272/// The result of trait evaluation. The order is important
272273/// here as the evaluation of a list is the maximum of the
273274/// evaluations.
275+ ///
276+ /// The evaluation results are ordered:
277+ /// - `EvaluatedToOk` implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
278+ /// - `EvaluatedToErr` implies `EvaluatedToRecur`
279+ /// - the "union" of evaluation results is equal to their maximum -
280+ /// all the "potential success" candidates can potentially succeed,
281+ /// so they are no-ops when unioned with a definite error, and within
282+ /// the categories it's easy to see that the unions are correct.
274283enum EvaluationResult {
275284 /// Evaluation successful
276285 EvaluatedToOk ,
277- /// Evaluation failed because of recursion - treated as ambiguous
278- EvaluatedToUnknown ,
279- /// Evaluation is known to be ambiguous
286+ /// Evaluation is known to be ambiguous - it *might* hold for some
287+ /// assignment of inference variables, but it might not.
288+ ///
289+ /// While this has the same meaning as `EvaluatedToUnknown` - we can't
290+ /// know whether this obligation holds or not - it is the result we
291+ /// would get with an empty stack, and therefore is cacheable.
280292 EvaluatedToAmbig ,
293+ /// Evaluation failed because of recursion involving inference
294+ /// variables. We are somewhat imprecise there, so we don't actually
295+ /// know the real result.
296+ ///
297+ /// This can't be trivially cached for the same reason as `EvaluatedToRecur`.
298+ EvaluatedToUnknown ,
299+ /// Evaluation failed because we encountered an obligation we are already
300+ /// trying to prove on this branch.
301+ ///
302+ /// We know this branch can't be a part of a minimal proof-tree for
303+ /// the "root" of our cycle, because then we could cut out the recursion
304+ /// and maintain a valid proof tree. However, this does not mean
305+ /// that all the obligations on this branch do not hold - it's possible
306+ /// that we entered this branch "speculatively", and that there
307+ /// might be some other way to prove this obligation that does not
308+ /// go through this cycle - so we can't cache this as a failure.
309+ ///
310+ /// For example, suppose we have this:
311+ ///
312+ /// ```rust,ignore (pseudo-Rust)
313+ /// pub trait Trait { fn xyz(); }
314+ /// // This impl is "useless", but we can still have
315+ /// // an `impl Trait for SomeUnsizedType` somewhere.
316+ /// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
317+ ///
318+ /// pub fn foo<T: Trait + ?Sized>() {
319+ /// <T as Trait>::xyz();
320+ /// }
321+ /// ```
322+ ///
323+ /// When checking `foo`, we have to prove `T: Trait`. This basically
324+ /// translates into this:
325+ ///
326+ /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
327+ ///
328+ /// When we try to prove it, we first go the first option, which
329+ /// recurses. This shows us that the impl is "useless" - it won't
330+ /// tell us that `T: Trait` unless it already implemented `Trait`
331+ /// by some other means. However, that does not prevent `T: Trait`
332+ /// does not hold, because of the bound (which can indeed be satisfied
333+ /// by `SomeUnsizedType` from another crate).
334+ ///
335+ /// FIXME: when an `EvaluatedToRecur` goes past its parent root, we
336+ /// ought to convert it to an `EvaluatedToErr`, because we know
337+ /// there definitely isn't a proof tree for that obligation. Not
338+ /// doing so is still sound - there isn't any proof tree, so the
339+ /// branch still can't be a part of a minimal one - but does not
340+ /// re-enable caching.
341+ EvaluatedToRecur ,
281342 /// Evaluation failed
282343 EvaluatedToErr ,
283344}
284345
346+ impl EvaluationResult {
347+ fn may_apply ( self ) -> bool {
348+ match self {
349+ EvaluatedToOk |
350+ EvaluatedToAmbig |
351+ EvaluatedToUnknown => true ,
352+
353+ EvaluatedToErr |
354+ EvaluatedToRecur => false
355+ }
356+ }
357+
358+ fn is_stack_dependent ( self ) -> bool {
359+ match self {
360+ EvaluatedToUnknown |
361+ EvaluatedToRecur => true ,
362+
363+ EvaluatedToOk |
364+ EvaluatedToAmbig |
365+ EvaluatedToErr => false ,
366+ }
367+ }
368+ }
369+
285370#[ derive( Clone ) ]
286371pub struct EvaluationCache < ' tcx > {
287372 hashmap : RefCell < FxHashMap < ty:: PolyTraitRef < ' tcx > , EvaluationResult > >
@@ -492,15 +577,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
492577 let eval = self . evaluate_predicate_recursively ( stack, obligation) ;
493578 debug ! ( "evaluate_predicate_recursively({:?}) = {:?}" ,
494579 obligation, eval) ;
495- match eval {
496- EvaluatedToErr => { return EvaluatedToErr ; }
497- EvaluatedToAmbig => { result = EvaluatedToAmbig ; }
498- EvaluatedToUnknown => {
499- if result < EvaluatedToUnknown {
500- result = EvaluatedToUnknown ;
501- }
502- }
503- EvaluatedToOk => { }
580+ if let EvaluatedToErr = eval {
581+ // fast-path - EvaluatedToErr is the top of the lattice,
582+ // so we don't need to look on the other predicates.
583+ return EvaluatedToErr ;
584+ } else {
585+ result = cmp:: max ( result, eval) ;
504586 }
505587 }
506588 result
@@ -719,7 +801,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
719801 } else {
720802 debug ! ( "evaluate_stack({:?}) --> recursive, inductive" ,
721803 stack. fresh_trait_ref) ;
722- return EvaluatedToErr ;
804+ return EvaluatedToRecur ;
723805 }
724806 }
725807
@@ -807,10 +889,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
807889 result : EvaluationResult )
808890 {
809891 // Avoid caching results that depend on more than just the trait-ref:
810- // The stack can create EvaluatedToUnknown , and closure signatures
892+ // The stack can create recursion , and closure signatures
811893 // being yet uninferred can create "spurious" EvaluatedToAmbig
812894 // and EvaluatedToOk.
813- if result == EvaluatedToUnknown ||
895+ if result. is_stack_dependent ( ) ||
814896 ( ( result == EvaluatedToAmbig || result == EvaluatedToOk )
815897 && trait_ref. has_closure_types ( ) )
816898 {
@@ -3055,15 +3137,3 @@ impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> {
30553137 write ! ( f, "TraitObligationStack({:?})" , self . obligation)
30563138 }
30573139}
3058-
3059- impl EvaluationResult {
3060- fn may_apply ( & self ) -> bool {
3061- match * self {
3062- EvaluatedToOk |
3063- EvaluatedToAmbig |
3064- EvaluatedToUnknown => true ,
3065-
3066- EvaluatedToErr => false
3067- }
3068- }
3069- }
0 commit comments