]> git.lizzy.rs Git - rust.git/commitdiff
Make all predicates higher-ranked, not just trait references.
authorNiko Matsakis <niko@alum.mit.edu>
Sat, 13 Dec 2014 10:34:34 +0000 (05:34 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Fri, 19 Dec 2014 08:29:30 +0000 (03:29 -0500)
12 files changed:
src/librustc/metadata/tydecode.rs
src/librustc/metadata/tyencode.rs
src/librustc/middle/infer/higher_ranked/mod.rs
src/librustc/middle/infer/mod.rs
src/librustc/middle/traits/fulfill.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/ty.rs
src/librustc/middle/ty_fold.rs
src/librustc/util/ppaux.rs
src/librustc_typeck/check/vtable.rs
src/librustc_typeck/collect.rs
src/libsyntax/visit.rs

index f3d700f013d815bfb0960f142c651082dad90cb1..f2a41c48d1203753408e4b8d5cc94b5835a0d75d 100644 (file)
@@ -21,7 +21,7 @@
 use middle::region;
 use middle::subst;
 use middle::subst::VecPerParamSpace;
-use middle::ty::{mod, Ty};
+use middle::ty::{mod, AsPredicate, Ty};
 
 use std::rc::Rc;
 use std::str;
@@ -669,13 +669,13 @@ pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>,
                                 -> ty::Predicate<'tcx>
 {
     match next(st) {
-        't' => ty::Predicate::Trait(Rc::new(ty::Binder(parse_trait_ref(st, conv)))),
-        'e' => ty::Predicate::Equate(parse_ty(st, |x,y| conv(x,y)),
-                                     parse_ty(st, |x,y| conv(x,y))),
-        'r' => ty::Predicate::RegionOutlives(parse_region(st, |x,y| conv(x,y)),
-                                             parse_region(st, |x,y| conv(x,y))),
-        'o' => ty::Predicate::TypeOutlives(parse_ty(st, |x,y| conv(x,y)),
-                                           parse_region(st, |x,y| conv(x,y))),
+        't' => Rc::new(ty::Binder(parse_trait_ref(st, conv))).as_predicate(),
+        'e' => ty::Binder(ty::EquatePredicate(parse_ty(st, |x,y| conv(x,y)),
+                                              parse_ty(st, |x,y| conv(x,y)))).as_predicate(),
+        'r' => ty::Binder(ty::OutlivesPredicate(parse_region(st, |x,y| conv(x,y)),
+                                                parse_region(st, |x,y| conv(x,y)))).as_predicate(),
+        'o' => ty::Binder(ty::OutlivesPredicate(parse_ty(st, |x,y| conv(x,y)),
+                                                parse_region(st, |x,y| conv(x,y)))).as_predicate(),
         c => panic!("Encountered invalid character in metadata: {}", c)
     }
 }
index c6218e6fe94782bdd87cbbc80a79583993e12fac..5d7d85d4679d7c9d8ed6e46913a4467a36dd91e1 100644 (file)
@@ -427,17 +427,17 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
             mywrite!(w, "t");
             enc_trait_ref(w, cx, &trait_ref.0);
         }
-        ty::Predicate::Equate(a, b) => {
+        ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => {
             mywrite!(w, "e");
             enc_ty(w, cx, a);
             enc_ty(w, cx, b);
         }
-        ty::Predicate::RegionOutlives(a, b) => {
+        ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
             mywrite!(w, "r");
             enc_region(w, cx, a);
             enc_region(w, cx, b);
         }
-        ty::Predicate::TypeOutlives(a, b) => {
+        ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => {
             mywrite!(w, "o");
             enc_ty(w, cx, a);
             enc_region(w, cx, b);
index ca4a6b28c2a1cbeab20c37ac845d6a890e5c9d26..3a84890de4f4baa6b5b5928bb5955be2dc25a71b 100644 (file)
@@ -81,7 +81,7 @@ fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
 
             // Presuming type comparison succeeds, we need to check
             // that the skolemized regions do not "leak".
-            match self.infcx().leak_check(&skol_map, snapshot) {
+            match leak_check(self.infcx(), &skol_map, snapshot) {
                 Ok(()) => { }
                 Err((skol_br, tainted_region)) => {
                     if self.a_is_expected() {
index 0dfae4b882b7fa7c84d8829dc766f366db201a85..29021c0cca6b9a8f3b0a993080dc6dd0ea112037 100644 (file)
@@ -717,11 +717,40 @@ pub fn skolemize_late_bound_regions<T>(&self,
     pub fn leak_check(&self,
                       skol_map: &SkolemizationMap,
                       snapshot: &CombinedSnapshot)
-                      -> Result<(),(ty::BoundRegion,ty::Region)>
+                      -> ures<'tcx>
     {
         /*! See `higher_ranked::leak_check` */
 
-        higher_ranked::leak_check(self, skol_map, snapshot)
+        match higher_ranked::leak_check(self, skol_map, snapshot) {
+            Ok(()) => Ok(()),
+            Err((br, r)) => Err(ty::terr_regions_insufficiently_polymorphic(br, r))
+        }
+    }
+
+    pub fn equality_predicate(&self,
+                              span: Span,
+                              predicate: &ty::PolyEquatePredicate<'tcx>)
+                              -> ures<'tcx> {
+        self.try(|snapshot| {
+            let (ty::EquatePredicate(a, b), skol_map) =
+                self.skolemize_late_bound_regions(predicate, snapshot);
+            let origin = EquatePredicate(span);
+            let () = try!(mk_eqty(self, false, origin, a, b));
+            self.leak_check(&skol_map, snapshot)
+        })
+    }
+
+    pub fn region_outlives_predicate(&self,
+                                     span: Span,
+                                     predicate: &ty::PolyRegionOutlivesPredicate)
+                                     -> ures<'tcx> {
+        self.try(|snapshot| {
+            let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
+                self.skolemize_late_bound_regions(predicate, snapshot);
+            let origin = RelateRegionParamBound(span);
+            let () = mk_subr(self, origin, r_b, r_a); // `b : a` ==> `a <= b`
+            self.leak_check(&skol_map, snapshot)
+        })
     }
 
     pub fn next_ty_var_id(&self, diverging: bool) -> TyVid {
index 8433313cb37180ce817f36e05343e3fc3528037f..32d9056f7b778ec212c6e70db74b8407b7ed8ed7 100644 (file)
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use middle::infer::InferCtxt;
 use middle::mem_categorization::Typer;
 use middle::ty::{mod, Ty};
-use middle::infer::{mod, InferCtxt};
 use std::collections::HashSet;
 use std::collections::hash_map::{Occupied, Vacant};
 use std::default::Default;
@@ -329,30 +329,50 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
             }
         }
 
-        ty::Predicate::Equate(a, b) => {
-            let origin = infer::EquatePredicate(predicate.cause.span);
-            match infer::mk_eqty(selcx.infcx(), false, origin, a, b) {
-                Ok(()) => {
-                    true
-                }
+        ty::Predicate::Equate(ref binder) => {
+            match selcx.infcx().equality_predicate(predicate.cause.span, binder) {
+                Ok(()) => { }
                 Err(_) => {
                     errors.push(
                         FulfillmentError::new(
                             predicate.clone(),
                             CodeSelectionError(Unimplemented)));
-                    true
                 }
             }
+            true
         }
 
-        ty::Predicate::RegionOutlives(r_a, r_b) => {
-            let origin = infer::RelateRegionParamBound(predicate.cause.span);
-            let () = infer::mk_subr(selcx.infcx(), origin, r_b, r_a); // `b : a` ==> `a <= b`
+        ty::Predicate::RegionOutlives(ref binder) => {
+            match selcx.infcx().region_outlives_predicate(predicate.cause.span, binder) {
+                Ok(()) => { }
+                Err(_) => {
+                    errors.push(
+                        FulfillmentError::new(
+                            predicate.clone(),
+                            CodeSelectionError(Unimplemented)));
+                }
+            }
+
             true
         }
 
-        ty::Predicate::TypeOutlives(t_a, r_b) => {
-            register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations);
+        ty::Predicate::TypeOutlives(ref binder) => {
+            // For now, we just check that there are no higher-ranked
+            // regions.  If there are, we will call this obligation an
+            // error. Eventually we should be able to support some
+            // cases here, I imagine (e.g., `for<'a> &'a int : 'a`).
+            //
+            // TODO This is overly conservative, but good enough for
+            // now.
+            if ty::count_late_bound_regions(selcx.tcx(), binder) != 0 {
+                errors.push(
+                    FulfillmentError::new(
+                        predicate.clone(),
+                        CodeSelectionError(Unimplemented)));
+            } else {
+                let ty::OutlivesPredicate(t_a, r_b) = binder.0;
+                register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations);
+            }
             true
         }
     }
@@ -385,3 +405,4 @@ fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>,
     }
 
 }
+
index e0a40901ee8517d8bac0aca9db79154f91375232..0bda04237b631b187b8b8506c95c5e1ff46ef86d 100644 (file)
@@ -28,7 +28,7 @@
 use middle::fast_reject;
 use middle::mem_categorization::Typer;
 use middle::subst::{Subst, Substs, VecPerParamSpace};
-use middle::ty::{mod, Ty, RegionEscape};
+use middle::ty::{mod, AsPredicate, RegionEscape, Ty};
 use middle::infer;
 use middle::infer::{InferCtxt, TypeFreshener};
 use middle::ty_fold::TypeFoldable;
@@ -288,8 +288,11 @@ fn evaluate_predicate_recursively<'o>(&mut self,
                 self.evaluate_obligation_recursively(previous_stack, &obligation)
             }
 
-            ty::Predicate::Equate(a, b) => {
-                match infer::can_mk_eqty(self.infcx, a, b) {
+            ty::Predicate::Equate(ref p) => {
+                let result = self.infcx.probe(|| {
+                    self.infcx.equality_predicate(obligation.cause.span, p)
+                });
+                match result {
                     Ok(()) => EvaluatedToOk,
                     Err(_) => EvaluatedToErr(Unimplemented),
                 }
@@ -1447,8 +1450,8 @@ fn vtable_builtin_data(&mut self,
             obligations.push(Obligation {
                 cause: obligation.cause,
                 recursion_depth: obligation.recursion_depth+1,
-                trait_ref: ty::Predicate::TypeOutlives(obligation.self_ty(),
-                                                       ty::ReStatic)
+                trait_ref: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(),
+                                                            ty::ReStatic)).as_predicate(),
             });
         }
 
index a24992e89e35dc632aa7bc7a9c3fd2887d536a6e..91247d8b73e41babf68b30ee463d01cb96524734 100644 (file)
@@ -1689,23 +1689,60 @@ pub enum Predicate<'tcx> {
     Trait(Rc<PolyTraitRef<'tcx>>),
 
     /// where `T1 == T2`.
-    Equate(/* T1 */ Ty<'tcx>, /* T2 */ Ty<'tcx>),
+    Equate(PolyEquatePredicate<'tcx>),
 
     /// where 'a : 'b
-    RegionOutlives(/* 'a */ Region, /* 'b */ Region),
+    RegionOutlives(PolyRegionOutlivesPredicate),
 
     /// where T : 'a
-    TypeOutlives(Ty<'tcx>, Region),
+    TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
+}
+
+#[deriving(Clone, PartialEq, Eq, Hash, Show)]
+pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1`
+pub type PolyEquatePredicate<'tcx> = ty::Binder<EquatePredicate<'tcx>>;
+
+#[deriving(Clone, PartialEq, Eq, Hash, Show)]
+pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
+pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
+pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate<ty::Region, ty::Region>;
+pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region>;
+
+pub trait AsPredicate<'tcx> {
+    fn as_predicate(&self) -> Predicate<'tcx>;
+}
+
+impl<'tcx> AsPredicate<'tcx> for Rc<PolyTraitRef<'tcx>> {
+    fn as_predicate(&self) -> Predicate<'tcx> {
+        Predicate::Trait(self.clone())
+    }
+}
+
+impl<'tcx> AsPredicate<'tcx> for PolyEquatePredicate<'tcx> {
+    fn as_predicate(&self) -> Predicate<'tcx> {
+        Predicate::Equate(self.clone())
+    }
+}
+
+impl<'tcx> AsPredicate<'tcx> for PolyRegionOutlivesPredicate {
+    fn as_predicate(&self) -> Predicate<'tcx> {
+        Predicate::RegionOutlives(self.clone())
+    }
+}
+
+impl<'tcx> AsPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
+    fn as_predicate(&self) -> Predicate<'tcx> {
+        Predicate::TypeOutlives(self.clone())
+    }
 }
 
 impl<'tcx> Predicate<'tcx> {
     pub fn has_escaping_regions(&self) -> bool {
         match *self {
             Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(),
-            Predicate::Equate(a, b) => (ty::type_has_escaping_regions(a) ||
-                                        ty::type_has_escaping_regions(b)),
-            Predicate::RegionOutlives(a, b) => a.escapes_depth(0) || b.escapes_depth(0),
-            Predicate::TypeOutlives(a, b) => ty::type_has_escaping_regions(a) || b.escapes_depth(0),
+            Predicate::Equate(ref p) => p.has_escaping_regions(),
+            Predicate::RegionOutlives(ref p) => p.has_escaping_regions(),
+            Predicate::TypeOutlives(ref p) => p.has_escaping_regions(),
         }
     }
 
@@ -5208,17 +5245,20 @@ pub fn predicates<'tcx>(
 
     for builtin_bound in bounds.builtin_bounds.iter() {
         match traits::poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) {
-            Ok(trait_ref) => { vec.push(Predicate::Trait(trait_ref)); }
+            Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); }
             Err(ErrorReported) => { }
         }
     }
 
     for &region_bound in bounds.region_bounds.iter() {
-        vec.push(Predicate::TypeOutlives(param_ty, region_bound));
+        // account for the binder being introduced below; no need to shift `param_ty`
+        // because, at present at least, it can only refer to early-bound regions
+        let region_bound = ty_fold::shift_region(region_bound, 1);
+        vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).as_predicate());
     }
 
     for bound_trait_ref in bounds.trait_bounds.iter() {
-        vec.push(Predicate::Trait((*bound_trait_ref).clone()));
+        vec.push(bound_trait_ref.as_predicate());
     }
 
     vec
@@ -5595,19 +5635,27 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
     ty::required_region_bounds(tcx, open_ty, predicates)
 }
 
-/// Given a type which must meet the builtin bounds and trait bounds, returns a set of lifetimes
-/// which the type must outlive.
+/// Given a set of predicates that apply to an object type, returns
+/// the region bounds that the (erased) `Self` type must
+/// outlive. Precisely *because* the `Self` type is erased, the
+/// parameter `erased_self_ty` must be supplied to indicate what type
+/// has been used to represent `Self` in the predicates
+/// themselves. This should really be a unique type; `FreshTy(0)` is a
+/// popular choice (see `object_region_bounds` above).
 ///
-/// Requires that trait definitions have been processed.
+/// Requires that trait definitions have been processed so that we can
+/// elaborate predicates and walk supertraits.
 pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
-                                    param_ty: Ty<'tcx>,
+                                    erased_self_ty: Ty<'tcx>,
                                     predicates: Vec<ty::Predicate<'tcx>>)
                                     -> Vec<ty::Region>
 {
-    debug!("required_region_bounds(param_ty={}, predicates={})",
-           param_ty.repr(tcx),
+    debug!("required_region_bounds(erased_self_ty={}, predicates={})",
+           erased_self_ty.repr(tcx),
            predicates.repr(tcx));
 
+    assert!(!erased_self_ty.has_escaping_regions());
+
     traits::elaborate_predicates(tcx, predicates)
         .filter_map(|predicate| {
             match predicate {
@@ -5616,9 +5664,22 @@ pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>,
                 ty::Predicate::RegionOutlives(..) => {
                     None
                 }
-                ty::Predicate::TypeOutlives(t, r) => {
-                    if t == param_ty {
-                        Some(r)
+                ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => {
+                    // Search for a bound of the form `erased_self_ty
+                    // : 'a`, but be wary of something like `for<'a>
+                    // erased_self_ty : 'a` (we interpret a
+                    // higher-ranked bound like that as 'static,
+                    // though at present the code in `fulfill.rs`
+                    // considers such bounds to be unsatisfiable, so
+                    // it's kind of a moot point since you could never
+                    // construct such an object, but this seems
+                    // correct even if that code changes).
+                    if t == erased_self_ty && !r.has_escaping_regions() {
+                        if r.has_escaping_regions() {
+                            Some(ty::ReStatic)
+                        } else {
+                            Some(r)
+                        }
                     } else {
                         None
                     }
@@ -6100,16 +6161,20 @@ fn record_region_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, bounds: &GenericBounds<'tcx>
                 Predicate::Trait(..) | Predicate::Equate(..) | Predicate::TypeOutlives(..) => {
                     // No region bounds here
                 }
-                Predicate::RegionOutlives(ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
-                    // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
-                    tcx.region_maps.relate_free_regions(fr_b, fr_a);
-                }
-                Predicate::RegionOutlives(r_a, r_b) => {
-                    // All named regions are instantiated with free regions.
-                    tcx.sess.bug(
-                        format!("record_region_bounds: non free region: {} / {}",
-                                r_a.repr(tcx),
-                                r_b.repr(tcx)).as_slice());
+                Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
+                    match (r_a, r_b) {
+                        (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
+                            // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
+                            tcx.region_maps.relate_free_regions(fr_b, fr_a);
+                        }
+                        _ => {
+                            // All named regions are instantiated with free regions.
+                            tcx.sess.bug(
+                                format!("record_region_bounds: non free region: {} / {}",
+                                        r_a.repr(tcx),
+                                        r_b.repr(tcx)).as_slice());
+                        }
+                    }
                 }
             }
         }
@@ -6313,6 +6378,16 @@ pub fn liberate_late_bound_regions<'tcx, T>(
         |br, _| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0
 }
 
+pub fn count_late_bound_regions<'tcx, T>(
+    tcx: &ty::ctxt<'tcx>,
+    value: &Binder<T>)
+    -> uint
+    where T : TypeFoldable<'tcx> + Repr<'tcx>
+{
+    let (_, skol_map) = replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic);
+    skol_map.len()
+}
+
 /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
 /// method lookup and a few other places where precise region relationships are not required.
 pub fn erase_late_bound_regions<'tcx, T>(
@@ -6454,9 +6529,9 @@ impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
         match *self {
             Predicate::Trait(ref a) => a.repr(tcx),
-            Predicate::Equate(a, b) => format!("Equate({},{})", a.repr(tcx), b.repr(tcx)),
-            Predicate::RegionOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)),
-            Predicate::TypeOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)),
+            Predicate::Equate(ref pair) => format!("Equate({})", pair.repr(tcx)),
+            Predicate::RegionOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)),
+            Predicate::TypeOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)),
         }
     }
 }
@@ -6586,9 +6661,15 @@ fn has_regions_escaping_depth(&self, depth: uint) -> bool {
     }
 }
 
-impl<T:RegionEscape> Binder<T> {
-    pub fn has_bound_regions(&self) -> bool {
-        self.0.has_regions_escaping_depth(0)
+impl<'tcx> RegionEscape for EquatePredicate<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: uint) -> bool {
+        self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<T:RegionEscape,U:RegionEscape> RegionEscape for OutlivesPredicate<T,U> {
+    fn has_regions_escaping_depth(&self, depth: uint) -> bool {
+        self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
     }
 }
 
index 6d6dc1d426ad6b40a4f3a11d0e02c18c0dee6ded..496a0badd82368532948f68e5cbb7801018c3dbe 100644 (file)
@@ -409,15 +409,12 @@ fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Predicate<'tcx>
         match *self {
             ty::Predicate::Trait(ref a) =>
                 ty::Predicate::Trait(a.fold_with(folder)),
-            ty::Predicate::Equate(ref a, ref b) =>
-                ty::Predicate::Equate(a.fold_with(folder),
-                                        b.fold_with(folder)),
-            ty::Predicate::RegionOutlives(ref a, ref b) =>
-                ty::Predicate::RegionOutlives(a.fold_with(folder),
-                                                b.fold_with(folder)),
-            ty::Predicate::TypeOutlives(ref a, ref b) =>
-                ty::Predicate::TypeOutlives(a.fold_with(folder),
-                                              b.fold_with(folder)),
+            ty::Predicate::Equate(ref binder) =>
+                ty::Predicate::Equate(binder.fold_with(folder)),
+            ty::Predicate::RegionOutlives(ref binder) =>
+                ty::Predicate::RegionOutlives(binder.fold_with(folder)),
+            ty::Predicate::TypeOutlives(ref binder) =>
+                ty::Predicate::TypeOutlives(binder.fold_with(folder)),
         }
     }
 }
@@ -501,6 +498,23 @@ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableParamDa
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> {
+        ty::EquatePredicate(self.0.fold_with(folder),
+                            self.1.fold_with(folder))
+    }
+}
+
+impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
+    where T : TypeFoldable<'tcx>,
+          U : TypeFoldable<'tcx>,
+{
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::OutlivesPredicate<T,U> {
+        ty::OutlivesPredicate(self.0.fold_with(folder),
+                              self.1.fold_with(folder))
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // "super" routines: these are the default implementations for TypeFolder.
 //
index 134006bef0b75f088399230813365741e6038750..b0124977c9f1b9ff25a083591fbe11803b8eaf35 100644 (file)
@@ -1350,3 +1350,56 @@ fn repr(&self, tcx: &ctxt<'tcx>) -> String {
                     .connect(", "))
     }
 }
+
+impl<'tcx, T, U> Repr<'tcx> for ty::OutlivesPredicate<T,U>
+    where T : Repr<'tcx> + TypeFoldable<'tcx>,
+          U : Repr<'tcx> + TypeFoldable<'tcx>,
+{
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("OutlivesPredicate({}, {})",
+                self.0.repr(tcx),
+                self.1.repr(tcx))
+    }
+}
+
+impl<'tcx, T, U> UserString<'tcx> for ty::OutlivesPredicate<T,U>
+    where T : UserString<'tcx> + TypeFoldable<'tcx>,
+          U : UserString<'tcx> + TypeFoldable<'tcx>,
+{
+    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("{} : {}",
+                self.0.user_string(tcx),
+                self.1.user_string(tcx))
+    }
+}
+
+impl<'tcx> Repr<'tcx> for ty::EquatePredicate<'tcx> {
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("EquatePredicate({}, {})",
+                self.0.repr(tcx),
+                self.1.repr(tcx))
+    }
+}
+
+impl<'tcx> UserString<'tcx> for ty::EquatePredicate<'tcx> {
+    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("{} == {}",
+                self.0.user_string(tcx),
+                self.1.user_string(tcx))
+    }
+}
+
+impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> {
+    fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
+        match *self {
+            ty::Predicate::Trait(ref trait_ref) => {
+                format!("{} : {}",
+                        trait_ref.self_ty().user_string(tcx),
+                        trait_ref.user_string(tcx))
+            }
+            ty::Predicate::Equate(ref predicate) => predicate.user_string(tcx),
+            ty::Predicate::RegionOutlives(ref predicate) => predicate.user_string(tcx),
+            ty::Predicate::TypeOutlives(ref predicate) => predicate.user_string(tcx),
+        }
+    }
+}
index ff91093ab5f7224f372aafa8ffc38324afe3af8b..4db795a1fda5561913c14bec5cac2870bd3a3808 100644 (file)
@@ -315,36 +315,13 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     match *error {
         Overflow => {
             // We could track the stack here more precisely if we wanted, I imagine.
-            match obligation.trait_ref {
-                ty::Predicate::Trait(ref trait_ref) => {
-                    let trait_ref =
-                        fcx.infcx().resolve_type_vars_if_possible(&**trait_ref);
-                    fcx.tcx().sess.span_err(
-                        obligation.cause.span,
-                        format!(
-                            "overflow evaluating the trait `{}` for the type `{}`",
-                            trait_ref.user_string(fcx.tcx()),
-                            trait_ref.self_ty().user_string(fcx.tcx())).as_slice());
-                }
-
-                ty::Predicate::Equate(a, b) => {
-                    let a = fcx.infcx().resolve_type_vars_if_possible(&a);
-                    let b = fcx.infcx().resolve_type_vars_if_possible(&b);
-                    fcx.tcx().sess.span_err(
-                        obligation.cause.span,
-                        format!(
-                            "overflow checking whether the types `{}` and `{}` are equal",
-                            a.user_string(fcx.tcx()),
-                            b.user_string(fcx.tcx())).as_slice());
-                }
-
-                ty::Predicate::TypeOutlives(..) |
-                ty::Predicate::RegionOutlives(..) => {
-                    fcx.tcx().sess.span_err(
-                        obligation.cause.span,
-                        format!("overflow evaluating lifetime predicate").as_slice());
-                }
-            }
+            let predicate =
+                fcx.infcx().resolve_type_vars_if_possible(&obligation.trait_ref);
+            fcx.tcx().sess.span_err(
+                obligation.cause.span,
+                format!(
+                    "overflow evaluating the requirement `{}`",
+                    predicate.user_string(fcx.tcx())).as_slice());
 
             let current_limit = fcx.tcx().sess.recursion_limit.get();
             let suggested_limit = current_limit * 2;
@@ -359,8 +336,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         Unimplemented => {
             match obligation.trait_ref {
                 ty::Predicate::Trait(ref trait_ref) => {
-                    let trait_ref =
-                        fcx.infcx().resolve_type_vars_if_possible(&**trait_ref);
+                    let trait_ref = fcx.infcx().resolve_type_vars_if_possible(&**trait_ref);
                     if !ty::type_is_error(trait_ref.self_ty()) {
                         fcx.tcx().sess.span_err(
                             obligation.cause.span,
@@ -368,34 +344,44 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                 "the trait `{}` is not implemented for the type `{}`",
                                 trait_ref.user_string(fcx.tcx()),
                                 trait_ref.self_ty().user_string(fcx.tcx())).as_slice());
-                        note_obligation_cause(fcx, obligation);
                     }
                 }
 
-                ty::Predicate::Equate(a, b) => {
-                    let a = fcx.infcx().resolve_type_vars_if_possible(&a);
-                    let b = fcx.infcx().resolve_type_vars_if_possible(&b);
-                    let err = infer::can_mk_eqty(fcx.infcx(), a, b).unwrap_err();
+                ty::Predicate::Equate(ref predicate) => {
+                    let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate);
+                    let err = fcx.infcx().equality_predicate(obligation.cause.span,
+                                                             &predicate).unwrap_err();
+                    fcx.tcx().sess.span_err(
+                        obligation.cause.span,
+                        format!(
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate.user_string(fcx.tcx()),
+                            ty::type_err_to_str(fcx.tcx(), &err)).as_slice());
+                }
+
+                ty::Predicate::RegionOutlives(ref predicate) => {
+                    let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate);
+                    let err = fcx.infcx().region_outlives_predicate(obligation.cause.span,
+                                                                    &predicate).unwrap_err();
                     fcx.tcx().sess.span_err(
                         obligation.cause.span,
                         format!(
-                            "mismatched types: the types `{}` and `{}` are not equal ({})",
-                            a.user_string(fcx.tcx()),
-                            b.user_string(fcx.tcx()),
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate.user_string(fcx.tcx()),
                             ty::type_err_to_str(fcx.tcx(), &err)).as_slice());
                 }
 
-                ty::Predicate::TypeOutlives(..) |
-                ty::Predicate::RegionOutlives(..) => {
-                    // these kinds of predicates turn into
-                    // constraints, and hence errors show up in region
-                    // inference.
-                    fcx.tcx().sess.span_bug(
+                ty::Predicate::TypeOutlives(ref predicate) => {
+                    let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate);
+                    fcx.tcx().sess.span_err(
                         obligation.cause.span,
-                        format!("region predicate error {}",
-                                obligation.repr(fcx.tcx())).as_slice());
+                        format!(
+                            "the requirement `{}` is not satisfied",
+                            predicate.user_string(fcx.tcx())).as_slice());
                 }
             }
+
+            note_obligation_cause(fcx, obligation);
         }
         OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
             let expected_trait_ref =
index e4d93123a269169f05bd5c2613db0c5e0255ad02..485f0ca84304debebcd5e9ca1c73c4078ecbd410 100644 (file)
 use middle::resolve_lifetime;
 use middle::subst;
 use middle::subst::{Substs};
-use middle::ty::{ImplContainer, ImplOrTraitItemContainer, TraitContainer};
-use middle::ty::{Polytype};
-use middle::ty::{mod, Ty};
-use middle::ty_fold::TypeFolder;
+use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
+use middle::ty::{mod, Ty, Polytype};
+use middle::ty_fold::{mod, TypeFolder};
 use middle::infer;
 use rscope::*;
 use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
@@ -1920,8 +1919,12 @@ fn create_predicates<'tcx>(
         for region_param_def in result.regions.get_slice(space).iter() {
             let region = region_param_def.to_early_bound_region();
             for &bound_region in region_param_def.bounds.iter() {
-                result.predicates.push(space, ty::Predicate::RegionOutlives(region,
-                                                                            bound_region));
+                // account for new binder introduced in the predicate below; no need
+                // to shift `region` because it is never a late-bound region
+                let bound_region = ty_fold::shift_region(bound_region, 1);
+                result.predicates.push(
+                    space,
+                    ty::Binder(ty::OutlivesPredicate(region, bound_region)).as_predicate());
             }
         }
     }
index 95d7906b443544669577805f2cb183b3e36d3e9b..5a1a186c74c4eab99585f7ca6500d5aecb0f82ce 100644 (file)
@@ -105,8 +105,11 @@ fn visit_opt_lifetime_ref(&mut self,
             None => ()
         }
     }
+    fn visit_lifetime_bound(&mut self, lifetime: &'v Lifetime) {
+        walk_lifetime_bound(self, lifetime)
+    }
     fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) {
-        self.visit_name(lifetime.span, lifetime.name)
+        walk_lifetime_ref(self, lifetime)
     }
     fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) {
         walk_lifetime_def(self, lifetime)
@@ -214,10 +217,20 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V,
                                               lifetime_def: &'v LifetimeDef) {
     visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name);
     for bound in lifetime_def.bounds.iter() {
-        visitor.visit_lifetime_ref(bound);
+        visitor.visit_lifetime_bound(bound);
     }
 }
 
+pub fn walk_lifetime_bound<'v, V: Visitor<'v>>(visitor: &mut V,
+                                               lifetime_ref: &'v Lifetime) {
+    visitor.visit_lifetime_ref(lifetime_ref)
+}
+
+pub fn walk_lifetime_ref<'v, V: Visitor<'v>>(visitor: &mut V,
+                                             lifetime_ref: &'v Lifetime) {
+    visitor.visit_name(lifetime_ref.span, lifetime_ref.name)
+}
+
 pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V,
                                               explicit_self: &'v ExplicitSelf) {
     match explicit_self.node {
@@ -550,7 +563,7 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V,
             visitor.visit_poly_trait_ref(typ);
         }
         RegionTyParamBound(ref lifetime) => {
-            visitor.visit_lifetime_ref(lifetime);
+            visitor.visit_lifetime_bound(lifetime);
         }
     }
 }