@@ -327,7 +327,8 @@ enum BuiltinImplConditions<'tcx> {
327
327
/// evaluations.
328
328
///
329
329
/// The evaluation results are ordered:
330
- /// - `EvaluatedToOk` implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
330
+ /// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
331
+ /// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
331
332
/// - `EvaluatedToErr` implies `EvaluatedToRecur`
332
333
/// - the "union" of evaluation results is equal to their maximum -
333
334
/// all the "potential success" candidates can potentially succeed,
@@ -336,6 +337,8 @@ enum BuiltinImplConditions<'tcx> {
336
337
pub enum EvaluationResult {
337
338
/// Evaluation successful
338
339
EvaluatedToOk ,
340
+ /// Evaluation successful, but there were unevaluated region obligations
341
+ EvaluatedToOkModuloRegions ,
339
342
/// Evaluation is known to be ambiguous - it *might* hold for some
340
343
/// assignment of inference variables, but it might not.
341
344
///
@@ -399,9 +402,23 @@ pub enum EvaluationResult {
399
402
}
400
403
401
404
impl EvaluationResult {
405
+ /// True if this evaluation result is known to apply, even
406
+ /// considering outlives constraints.
407
+ pub fn must_apply_considering_regions ( self ) -> bool {
408
+ self == EvaluatedToOk
409
+ }
410
+
411
+ /// True if this evaluation result is known to apply, ignoring
412
+ /// outlives constraints.
413
+ pub fn must_apply_modulo_regions ( self ) -> bool {
414
+ self <= EvaluatedToOkModuloRegions
415
+ }
416
+
402
417
pub fn may_apply ( self ) -> bool {
403
418
match self {
404
- EvaluatedToOk | EvaluatedToAmbig | EvaluatedToUnknown => true ,
419
+ EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => {
420
+ true
421
+ }
405
422
406
423
EvaluatedToErr | EvaluatedToRecur => false ,
407
424
}
@@ -411,13 +428,14 @@ impl EvaluationResult {
411
428
match self {
412
429
EvaluatedToUnknown | EvaluatedToRecur => true ,
413
430
414
- EvaluatedToOk | EvaluatedToAmbig | EvaluatedToErr => false ,
431
+ EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false ,
415
432
}
416
433
}
417
434
}
418
435
419
436
impl_stable_hash_for ! ( enum self :: EvaluationResult {
420
437
EvaluatedToOk ,
438
+ EvaluatedToOkModuloRegions ,
421
439
EvaluatedToAmbig ,
422
440
EvaluatedToUnknown ,
423
441
EvaluatedToRecur ,
@@ -686,92 +704,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
686
704
None => Ok ( EvaluatedToAmbig ) ,
687
705
} ,
688
706
689
- ty:: Predicate :: TypeOutlives ( ref binder) => {
690
- assert ! ( !binder. has_escaping_bound_vars( ) ) ;
691
- // Check if the type has higher-ranked vars.
692
- if binder. skip_binder ( ) . 0 . has_escaping_bound_vars ( ) {
693
- // If so, this obligation is an error (for now). Eventually we should be
694
- // able to support additional cases here, like `for<'a> &'a str: 'a`.
695
-
696
- // NOTE: this hack is implemented in both trait fulfillment and
697
- // evaluation. If you fix it in one place, make sure you fix it
698
- // in the other.
699
-
700
- // We don't want to allow this sort of reasoning in intercrate
701
- // mode, for backwards-compatibility reasons.
702
- if self . intercrate . is_some ( ) {
703
- Ok ( EvaluatedToAmbig )
704
- } else {
705
- Ok ( EvaluatedToErr )
706
- }
707
- } else {
708
- // If the type has no late bound vars, then if we assign all
709
- // the inference variables in it to be 'static, then the type
710
- // will be 'static itself.
711
- //
712
- // Therefore, `staticize(T): 'a` holds for any `'a`, so this
713
- // obligation is fulfilled. Because evaluation works with
714
- // staticized types (yes I know this is involved with #21974),
715
- // we are 100% OK here.
716
- Ok ( EvaluatedToOk )
717
- }
718
- }
719
-
720
- ty:: Predicate :: RegionOutlives ( ref binder) => {
721
- let ty:: OutlivesPredicate ( r_a, r_b) = binder. skip_binder ( ) ;
722
-
723
- if r_a == r_b {
724
- // for<'a> 'a: 'a. OK
725
- Ok ( EvaluatedToOk )
726
- } else if * * r_a == ty:: ReStatic {
727
- // 'static: 'x always holds.
728
- //
729
- // This special case is handled somewhat inconsistently - if we
730
- // have an inference variable that is supposed to be equal to
731
- // `'static`, then we don't allow it to be equated to an LBR,
732
- // but if we have a literal `'static`, then we *do*.
733
- //
734
- // This is actually consistent with how our region inference works.
735
- //
736
- // It would appear that this sort of inconsistency would
737
- // cause "instability" problems with evaluation caching. However,
738
- // evaluation caching is only for trait predicates, and when
739
- // trait predicates create nested obligations, they contain
740
- // inference variables for all the regions in the trait - the
741
- // only way this codepath can be reached from trait predicate
742
- // evaluation is when the user typed an explicit `where 'static: 'a`
743
- // lifetime bound (in which case we want to return EvaluatedToOk).
744
- //
745
- // If we ever want to handle inference variables that might be
746
- // equatable with ReStatic, we need to make sure we are not confused by
747
- // technically-allowed-by-RFC-447-but-probably-should-not-be
748
- // impls such as
749
- // ```Rust
750
- // impl<'a, 's, T> X<'s> for T where T: Debug + 'a, 'a: 's
751
- // ```
752
- Ok ( EvaluatedToOk )
753
- } else if r_a. is_late_bound ( ) || r_b. is_late_bound ( ) {
754
- // There is no current way to prove `for<'a> 'a: 'x`
755
- // unless `'a = 'x`, because there are no bounds involving
756
- // lifetimes.
757
-
758
- // It might be possible to prove `for<'a> 'x: 'a` by forcing `'x`
759
- // to be `'static`. However, this is not currently done by type
760
- // inference unless `'x` is literally ReStatic. See the comment
761
- // above.
762
-
763
- // We don't want to allow this sort of reasoning in intercrate
764
- // mode, for backwards-compatibility reasons.
765
- if self . intercrate . is_some ( ) {
766
- Ok ( EvaluatedToAmbig )
767
- } else {
768
- Ok ( EvaluatedToErr )
769
- }
770
- } else {
771
- // Relating 2 inference variable regions. These will
772
- // always hold if our query is "staticized".
773
- Ok ( EvaluatedToOk )
774
- }
707
+ ty:: Predicate :: TypeOutlives ( ..) | ty:: Predicate :: RegionOutlives ( ..) => {
708
+ // we do not consider region relationships when
709
+ // evaluating trait matches
710
+ Ok ( EvaluatedToOkModuloRegions )
775
711
}
776
712
777
713
ty:: Predicate :: ObjectSafe ( trait_def_id) => {
@@ -985,6 +921,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
985
921
{
986
922
debug ! ( "evaluate_stack({:?}) --> recursive" , stack. fresh_trait_ref) ;
987
923
924
+ // Subtle: when checking for a coinductive cycle, we do
925
+ // not compare using the "freshened trait refs" (which
926
+ // have erased regions) but rather the fully explicit
927
+ // trait refs. This is important because it's only a cycle
928
+ // if the regions match exactly.
988
929
let cycle = stack. iter ( ) . skip ( 1 ) . take ( rec_index + 1 ) ;
989
930
let cycle = cycle. map ( |stack| ty:: Predicate :: Trait ( stack. obligation . predicate ) ) ;
990
931
if self . coinductive_match ( cycle) {
@@ -2324,7 +2265,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
2324
2265
// See if we can toss out `victim` based on specialization.
2325
2266
// This requires us to know *for sure* that the `other` impl applies
2326
2267
// i.e., EvaluatedToOk:
2327
- if other. evaluation == EvaluatedToOk {
2268
+ if other. evaluation . must_apply_modulo_regions ( ) {
2328
2269
match victim. candidate {
2329
2270
ImplCandidate ( victim_def) => {
2330
2271
let tcx = self . tcx ( ) . global_tcx ( ) ;
@@ -2351,7 +2292,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
2351
2292
ParamCandidate ( ref cand) => {
2352
2293
// Prefer these to a global where-clause bound
2353
2294
// (see issue #50825)
2354
- is_global ( cand) && other. evaluation == EvaluatedToOk
2295
+ is_global ( cand) && other. evaluation . must_apply_modulo_regions ( )
2355
2296
}
2356
2297
_ => false ,
2357
2298
}
0 commit comments