@@ -43,6 +43,7 @@ use middle::lang_items;
43
43
use rustc_data_structures:: bitvec:: BitVector ;
44
44
use rustc_data_structures:: snapshot_vec:: { SnapshotVecDelegate , SnapshotVec } ;
45
45
use std:: cell:: RefCell ;
46
+ use std:: cmp;
46
47
use std:: fmt;
47
48
use std:: marker:: PhantomData ;
48
49
use std:: mem;
@@ -271,17 +272,101 @@ enum BuiltinImplConditions<'tcx> {
271
272
/// The result of trait evaluation. The order is important
272
273
/// here as the evaluation of a list is the maximum of the
273
274
/// 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.
274
283
enum EvaluationResult {
275
284
/// Evaluation successful
276
285
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.
280
292
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 ,
281
342
/// Evaluation failed
282
343
EvaluatedToErr ,
283
344
}
284
345
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
+
285
370
#[ derive( Clone ) ]
286
371
pub struct EvaluationCache < ' tcx > {
287
372
hashmap : RefCell < FxHashMap < ty:: PolyTraitRef < ' tcx > , EvaluationResult > >
@@ -492,15 +577,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
492
577
let eval = self . evaluate_predicate_recursively ( stack, obligation) ;
493
578
debug ! ( "evaluate_predicate_recursively({:?}) = {:?}" ,
494
579
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) ;
504
586
}
505
587
}
506
588
result
@@ -719,7 +801,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
719
801
} else {
720
802
debug ! ( "evaluate_stack({:?}) --> recursive, inductive" ,
721
803
stack. fresh_trait_ref) ;
722
- return EvaluatedToErr ;
804
+ return EvaluatedToRecur ;
723
805
}
724
806
}
725
807
@@ -807,10 +889,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
807
889
result : EvaluationResult )
808
890
{
809
891
// 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
811
893
// being yet uninferred can create "spurious" EvaluatedToAmbig
812
894
// and EvaluatedToOk.
813
- if result == EvaluatedToUnknown ||
895
+ if result. is_stack_dependent ( ) ||
814
896
( ( result == EvaluatedToAmbig || result == EvaluatedToOk )
815
897
&& trait_ref. has_closure_types ( ) )
816
898
{
@@ -3055,15 +3137,3 @@ impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> {
3055
3137
write ! ( f, "TraitObligationStack({:?})" , self . obligation)
3056
3138
}
3057
3139
}
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