diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index f3d700f013d8..f2a41c48d120 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -21,7 +21,7 @@ pub use self::DefIdSource::*; 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) } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index c6218e6fe947..5d7d85d4679d 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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); diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index ca4a6b28c2a1..3a84890de4f4 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -81,7 +81,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // 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() { diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 0dfae4b882b7..29021c0cca6b 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -717,11 +717,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 { diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 8433313cb371..32d9056f7b77 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -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 } } - } - - 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` true } - ty::Predicate::TypeOutlives(t_a, r_b) => { - register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); + 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(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>, } } + diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index e0a40901ee85..0bda04237b63 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -28,7 +28,7 @@ use super::{util}; 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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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(), }); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index a24992e89e35..91247d8b73e4 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1689,23 +1689,60 @@ pub enum Predicate<'tcx> { Trait(Rc>), /// 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>; + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct OutlivesPredicate(pub A, pub B); // `A : B` +pub type PolyOutlivesPredicate = ty::Binder>; +pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; +pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; + +pub trait AsPredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx>; +} + +impl<'tcx> AsPredicate<'tcx> for Rc> { + 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 ®ion_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>) -> Vec { - 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 @@ pub fn construct_parameter_environment<'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) + -> 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 @@ impl<'tcx,T:RegionEscape> RegionEscape for Binder { } } -impl Binder { - 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 RegionEscape for OutlivesPredicate { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 6d6dc1d426ad..496a0badd823 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -409,15 +409,12 @@ impl<'tcx> TypeFoldable<'tcx> for 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 @@ impl<'tcx> TypeFoldable<'tcx> for traits::VtableParamData<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { + fn fold_with>(&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 + where T : TypeFoldable<'tcx>, + U : TypeFoldable<'tcx>, +{ + fn fold_with>(&self, folder: &mut F) -> ty::OutlivesPredicate { + ty::OutlivesPredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } +} + /////////////////////////////////////////////////////////////////////////// // "super" routines: these are the default implementations for TypeFolder. // diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 134006bef0b7..b0124977c9f1 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1350,3 +1350,56 @@ impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap .connect(", ")) } } + +impl<'tcx, T, U> Repr<'tcx> for ty::OutlivesPredicate + 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 + 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), + } + } +} diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index ff91093ab5f7..4db795a1fda5 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -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!( - "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::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!("region predicate error {}", - obligation.repr(fcx.tcx())).as_slice()); + format!( + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(fcx.tcx()), + ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); + } + + ty::Predicate::TypeOutlives(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + fcx.tcx().sess.span_err( + obligation.cause.span, + 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 = diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e4d93123a269..485f0ca84304 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -42,10 +42,9 @@ use middle::region; 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 ty_generics<'tcx,AC>(this: &AC, 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()); } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 95d7906b4435..5a1a186c74c4 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -105,8 +105,11 @@ pub trait Visitor<'v> { 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); } } }