diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index c1066aa899e..2bf58972967 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -164,6 +164,8 @@ impl<'tcx> FulfillmentContext<'tcx> { // debug output much nicer to read and so on. let obligation = infcx.resolve_type_vars_if_possible(&obligation); + assert!(!obligation.has_escaping_regions()); + if !self.duplicate_set.insert(obligation.predicate.clone()) { debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx)); return; diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index f299dc6aaff..6121a441992 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -172,7 +172,7 @@ struct SelectionCandidateSet<'tcx> { } enum BuiltinBoundConditions<'tcx> { - If(Vec>), + If(ty::Binder>>), ParameterBuiltin, AmbiguousBuiltin } @@ -293,7 +293,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // because if it is a closure type, it must be a closure type from // within this current fn, and hence none of the higher-ranked // lifetimes can appear inside the self-type. - let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let (closure_def_id, substs) = match self_ty.sty { ty::ty_closure(id, ref substs) => (id, substs.clone()), _ => { return; } @@ -1051,7 +1051,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => { return Ok(()); } }; - let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + // ok to skip binder because the substs on closure types never + // touch bound regions, they just capture the in-scope + // type/region parameters + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let (closure_def_id, substs) = match self_ty.sty { ty::ty_closure(id, ref substs) => (id, substs.clone()), ty::ty_infer(ty::TyVar(_)) => { @@ -1094,7 +1097,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(()); } - let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + // ok to skip binder because what we are inspecting doesn't involve bound regions + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); match self_ty.sty { ty::ty_infer(ty::TyVar(_)) => { debug!("assemble_fn_pointer_candidates: ambiguous self-type"); @@ -1126,8 +1130,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { - let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); - debug!("assemble_candidates_from_impls(self_ty={})", self_ty.repr(self.tcx())); + debug!("assemble_candidates_from_impls(obligation={})", obligation.repr(self.tcx())); let def_id = obligation.predicate.def_id(); let all_impls = self.all_impls(def_id); @@ -1153,8 +1156,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { - - let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + // OK to skip binder here because the tests we do below do not involve bound regions + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); debug!("assemble_candidates_from_default_impls(self_ty={})", self_ty.repr(self.tcx())); let def_id = obligation.predicate.def_id(); @@ -1224,10 +1227,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>) { - let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); - debug!("assemble_candidates_from_object_ty(self_ty={})", - self_ty.repr(self.tcx())); + self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()).repr(self.tcx())); // Object-safety candidates are only applicable to object-safe // traits. Including this check is useful because it helps @@ -1240,43 +1241,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - let poly_trait_ref = match self_ty.sty { - ty::ty_trait(ref data) => { - match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { - Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => { - if data.bounds.builtin_bounds.contains(&bound) { - debug!("assemble_candidates_from_object_ty: matched builtin bound, \ - pushing candidate"); - candidates.vec.push(BuiltinObjectCandidate); - return; + self.infcx.try(|snapshot| { + let bound_self_ty = + self.infcx.resolve_type_vars_if_possible(&obligation.self_ty()); + let (self_ty, _) = + self.infcx().skolemize_late_bound_regions(&bound_self_ty, snapshot); + let poly_trait_ref = match self_ty.sty { + ty::ty_trait(ref data) => { + match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { + Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => { + if data.bounds.builtin_bounds.contains(&bound) { + debug!("assemble_candidates_from_object_ty: matched builtin bound, \ + pushing candidate"); + candidates.vec.push(BuiltinObjectCandidate); + return Ok(()); + } } + _ => {} } - _ => {} + + data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) } + ty::ty_infer(ty::TyVar(_)) => { + debug!("assemble_candidates_from_object_ty: ambiguous"); + candidates.ambiguous = true; // could wind up being an object type + return Ok(()); + } + _ => { + return Ok(()); + } + }; - data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) - } - ty::ty_infer(ty::TyVar(_)) => { - debug!("assemble_candidates_from_object_ty: ambiguous"); - candidates.ambiguous = true; // could wind up being an object type - return; - } - _ => { - return; - } - }; + debug!("assemble_candidates_from_object_ty: poly_trait_ref={}", + poly_trait_ref.repr(self.tcx())); - debug!("assemble_candidates_from_object_ty: poly_trait_ref={}", - poly_trait_ref.repr(self.tcx())); + // see whether the object trait can be upcast to the trait we are looking for + let upcast_trait_refs = self.upcast(poly_trait_ref, obligation); + if upcast_trait_refs.len() > 1 { + // can be upcast in many ways; need more type information + candidates.ambiguous = true; + } else if upcast_trait_refs.len() == 1 { + candidates.vec.push(ObjectCandidate); + } - // see whether the object trait can be upcast to the trait we are looking for - let upcast_trait_refs = self.upcast(poly_trait_ref, obligation); - if upcast_trait_refs.len() > 1 { - // can be upcast in many ways; need more type information - candidates.ambiguous = true; - } else if upcast_trait_refs.len() == 1 { - candidates.vec.push(ObjectCandidate); - } + Ok::<(),()>(()) + }).unwrap(); } /////////////////////////////////////////////////////////////////////////// @@ -1411,23 +1420,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty()); return match self_ty.sty { - ty::ty_infer(ty::IntVar(_)) - | ty::ty_infer(ty::FloatVar(_)) - | ty::ty_uint(_) - | ty::ty_int(_) - | ty::ty_bool - | ty::ty_float(_) - | ty::ty_bare_fn(..) - | ty::ty_char => { + ty::ty_infer(ty::IntVar(_)) | + ty::ty_infer(ty::FloatVar(_)) | + ty::ty_uint(_) | + ty::ty_int(_) | + ty::ty_bool | + ty::ty_float(_) | + ty::ty_bare_fn(..) | + ty::ty_char => { // safe for everything - Ok(If(Vec::new())) + ok_if(Vec::new()) } ty::ty_uniq(_) => { // Box match bound { ty::BoundCopy => Err(Unimplemented), - ty::BoundSized => Ok(If(Vec::new())), + ty::BoundSized => ok_if(Vec::new()), ty::BoundSync | ty::BoundSend => { self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); @@ -1437,7 +1446,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ty_ptr(..) => { // *const T, *mut T match bound { - ty::BoundCopy | ty::BoundSized => Ok(If(Vec::new())), + ty::BoundCopy | ty::BoundSized => ok_if(Vec::new()), ty::BoundSync | ty::BoundSend => { self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); @@ -1450,7 +1459,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundSized => Err(Unimplemented), ty::BoundCopy => { if data.bounds.builtin_bounds.contains(&bound) { - Ok(If(Vec::new())) + ok_if(Vec::new()) } else { // Recursively check all supertraits to find out if any further // bounds are required and thus we must fulfill. @@ -1460,7 +1469,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let desired_def_id = obligation.predicate.def_id(); for tr in util::supertraits(self.tcx(), principal) { if tr.def_id() == desired_def_id { - return Ok(If(Vec::new())) + return ok_if(Vec::new()) } } @@ -1482,11 +1491,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ast::MutMutable => Err(Unimplemented), // &T is always copyable - ast::MutImmutable => Ok(If(Vec::new())), + ast::MutImmutable => ok_if(Vec::new()), } } - ty::BoundSized => Ok(If(Vec::new())), + ty::BoundSized => ok_if(Vec::new()), ty::BoundSync | ty::BoundSend => { self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()"); @@ -1500,7 +1509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundCopy => { match *len { // [T, ..n] is copy iff T is copy - Some(_) => Ok(If(vec![element_ty])), + Some(_) => ok_if(vec![element_ty]), // [T] is unsized and hence affine None => Err(Unimplemented), @@ -1509,7 +1518,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundSized => { if len.is_some() { - Ok(If(Vec::new())) + ok_if(Vec::new()) } else { Err(Unimplemented) } @@ -1533,7 +1542,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - ty::ty_tup(ref tys) => Ok(If(tys.clone())), + ty::ty_tup(ref tys) => ok_if(tys.clone()), ty::ty_closure(def_id, substs) => { // FIXME -- This case is tricky. In the case of by-ref @@ -1558,11 +1567,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // unsized, so the closure struct as a whole must be // Sized. if bound == ty::BoundSized { - return Ok(If(Vec::new())); + return ok_if(Vec::new()); } match self.closure_typer.closure_upvars(def_id, substs) { - Some(upvars) => Ok(If(upvars.iter().map(|c| c.ty).collect())), + Some(upvars) => ok_if(upvars.iter().map(|c| c.ty).collect()), None => { debug!("assemble_builtin_bound_candidates: no upvar types available yet"); Ok(AmbiguousBuiltin) @@ -1604,7 +1613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(AmbiguousBuiltin) } - ty::ty_err => Ok(If(Vec::new())), + ty::ty_err => ok_if(Vec::new()), ty::ty_infer(ty::FreshTy(_)) | ty::ty_infer(ty::FreshIntTy(_)) => { @@ -1615,6 +1624,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; + fn ok_if<'tcx>(v: Vec>) + -> Result, SelectionError<'tcx>> { + Ok(If(ty::Binder(v))) + } + fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound, types: Vec>) -> Result, SelectionError<'tcx>> @@ -1625,7 +1639,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundCopy => Ok(ParameterBuiltin), // Sized if all the component types are sized. - ty::BoundSized => Ok(If(types)), + ty::BoundSized => ok_if(types), // Shouldn't be coming through here. ty::BoundSend | ty::BoundSync => unreachable!(), @@ -1728,8 +1742,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn collect_predicates_for_types(&mut self, obligation: &TraitObligation<'tcx>, trait_def_id: ast::DefId, - types: Vec>) -> Vec> { - + types: ty::Binder>>) + -> Vec> + { let derived_cause = match self.tcx().lang_items.to_builtin_kind(trait_def_id) { Some(_) => { self.derived_cause(obligation, BuiltinDerivedObligation) @@ -1739,43 +1754,52 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; - let normalized = project::normalize_with_depth(self, obligation.cause.clone(), - obligation.recursion_depth + 1, - &types); + // Because the types were potentially derived from + // higher-ranked obligations they may reference late-bound + // regions. For example, `for<'a> Foo<&'a int> : Copy` would + // yield a type like `for<'a> &'a int`. In general, we + // maintain the invariant that we never manipulate bound + // regions, so we have to process these bound regions somehow. + // + // The strategy is to: + // + // 1. Instantiate those regions to skolemized regions (e.g., + // `for<'a> &'a int` becomes `&0 int`. + // 2. Produce something like `&'0 int : Copy` + // 3. Re-bind the regions back to `for<'a> &'a int : Copy` - let obligations = normalized.value.iter().map(|&nested_ty| { - // the obligation might be higher-ranked, e.g. for<'a> &'a - // int : Copy. In that case, we will wind up with - // late-bound regions in the `nested` vector. So for each - // one we instantiate to a skolemized region, do our work - // to produce something like `&'0 int : Copy`, and then - // re-bind it. This is a bit of busy-work but preserves - // the invariant that we only manipulate free regions, not - // bound ones. + // Move the binder into the individual types + let bound_types: Vec>> = + types.skip_binder() + .iter() + .map(|&nested_ty| ty::Binder(nested_ty)) + .collect(); + + // For each type, produce a vector of resulting obligations + let obligations: Result>, _> = bound_types.iter().map(|nested_ty| { self.infcx.try(|snapshot| { let (skol_ty, skol_map) = - self.infcx().skolemize_late_bound_regions(&ty::Binder(nested_ty), snapshot); - let skol_predicate = - util::predicate_for_trait_def( - self.tcx(), - derived_cause.clone(), - trait_def_id, - obligation.recursion_depth + 1, - skol_ty); - match skol_predicate { - Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot, - &skol_predicate)), - Err(ErrorReported) => Err(ErrorReported) - } + self.infcx().skolemize_late_bound_regions(nested_ty, snapshot); + let Normalized { value: normalized_ty, mut obligations } = + project::normalize_with_depth(self, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &skol_ty); + let skol_obligation = + try!(util::predicate_for_trait_def(self.tcx(), + derived_cause.clone(), + trait_def_id, + obligation.recursion_depth + 1, + normalized_ty)); + obligations.push(skol_obligation); + Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations)) }) - }).collect::>, _>>(); + }).collect(); + // Flatten those vectors (couldn't do it above due `collect`) match obligations { - Ok(mut obls) => { - obls.push_all(&normalized.obligations); - obls - }, - Err(ErrorReported) => Vec::new() + Ok(obligations) => obligations.into_iter().flat_map(|o| o.into_iter()).collect(), + Err(ErrorReported) => Vec::new(), } } @@ -1919,7 +1943,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn vtable_builtin_data(&mut self, obligation: &TraitObligation<'tcx>, bound: ty::BuiltinBound, - nested: Vec>) + nested: ty::Binder>>) -> VtableBuiltinData> { let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) { @@ -1953,9 +1977,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.repr(self.tcx()), trait_def_id.repr(self.tcx())); - let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty()); + // binder is moved below + let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); match self.constituent_types_for_ty(self_ty) { - Some(types) => self.vtable_default_impl(obligation, trait_def_id, types), + Some(types) => self.vtable_default_impl(obligation, trait_def_id, ty::Binder(types)), None => { self.tcx().sess.bug( &format!( @@ -1976,10 +2001,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { assert!(ty::has_attr(self.tcx(), trait_def_id, "rustc_reflect_like")); - let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty()); + // OK to skip binder, it is reintroduced below + let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); match self_ty.sty { ty::ty_trait(ref data) => { - // OK to skip the binder, since vtable_default_impl reintroduces it + // OK to skip the binder, it is reintroduced below let input_types = data.principal.skip_binder().substs.types.get_slice(TypeSpace); let assoc_types = data.bounds.projection_bounds .iter() @@ -1987,6 +2013,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let all_types: Vec<_> = input_types.iter().cloned() .chain(assoc_types) .collect(); + + // reintroduce the two binding levels we skipped, then flatten into one + let all_types = ty::Binder(ty::Binder(all_types)); + let all_types = ty::flatten_late_bound_regions(self.tcx(), &all_types); + self.vtable_default_impl(obligation, trait_def_id, all_types) } _ => { @@ -2002,29 +2033,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn vtable_default_impl(&mut self, obligation: &TraitObligation<'tcx>, trait_def_id: ast::DefId, - nested: Vec>) + nested: ty::Binder>>) -> VtableDefaultImplData> { + debug!("vtable_default_impl_data: nested={}", nested.repr(self.tcx())); let mut obligations = self.collect_predicates_for_types(obligation, trait_def_id, nested); - let _: Result<(),()> = self.infcx.try(|snapshot| { - let (_, skol_map) = - self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot); - - let substs = obligation.predicate.to_poly_trait_ref().substs(); - let trait_obligations = self.impl_or_trait_obligations(obligation.cause.clone(), - obligation.recursion_depth + 1, - trait_def_id, - substs, - skol_map, - snapshot); - obligations.push_all(trait_obligations.as_slice()); - Ok(()) + let trait_obligations: Result,()> = self.infcx.try(|snapshot| { + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let (trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); + Ok(self.impl_or_trait_obligations(obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_def_id, + &trait_ref.substs, + skol_map, + snapshot)) }); + obligations.extend(trait_obligations.unwrap().into_iter()); // no Errors in that code above + debug!("vtable_default_impl_data: obligations={}", obligations.repr(self.tcx())); VtableDefaultImplData { @@ -2098,7 +2129,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("confirm_object_candidate({})", obligation.repr(self.tcx())); - let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + // FIXME skipping binder here seems wrong -- we should + // probably flatten the binder from the obligation and the + // binder from the object. Have to try to make a broken test + // case that results. -nmatsakis + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let poly_trait_ref = match self_ty.sty { ty::ty_trait(ref data) => { data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) @@ -2136,15 +2171,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("confirm_fn_pointer_candidate({})", obligation.repr(self.tcx())); - let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + // ok to skip binder; it is reintroduced below + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let sig = ty::ty_fn_sig(self_ty); - let ty::Binder((trait_ref, _)) = + let trait_ref = util::closure_trait_ref_and_return_type(self.tcx(), obligation.predicate.def_id(), self_ty, sig, - util::TupleArgumentsFlag::Yes); - let trait_ref = ty::Binder(trait_ref); + util::TupleArgumentsFlag::Yes) + .map_bound(|(trait_ref, _)| trait_ref); try!(self.confirm_poly_trait_refs(obligation.cause.clone(), obligation.predicate.to_poly_trait_ref(), @@ -2499,6 +2535,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { snapshot: &infer::CombinedSnapshot) -> VecPerParamSpace> { + debug!("impl_or_trait_obligations(def_id={})", def_id.repr(self.tcx())); + let predicates = ty::lookup_predicates(self.tcx(), def_id); let predicates = predicates.instantiate(self.tcx(), substs); let predicates = normalize_with_depth(self, cause.clone(), recursion_depth, &predicates); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 92b444e85d8..3572ca89acc 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1108,16 +1108,16 @@ pub type PolyFnSig<'tcx> = Binder>; impl<'tcx> PolyFnSig<'tcx> { pub fn inputs(&self) -> ty::Binder>> { - ty::Binder(self.0.inputs.clone()) + self.map_bound_ref(|fn_sig| fn_sig.inputs.clone()) } pub fn input(&self, index: uint) -> ty::Binder> { - ty::Binder(self.0.inputs[index]) + self.map_bound_ref(|fn_sig| fn_sig.inputs[index]) } pub fn output(&self) -> ty::Binder> { - ty::Binder(self.0.output.clone()) + self.map_bound_ref(|fn_sig| fn_sig.output.clone()) } pub fn variadic(&self) -> bool { - self.0.variadic + self.skip_binder().variadic } } @@ -1519,6 +1519,22 @@ impl Binder { pub fn skip_binder(&self) -> &T { &self.0 } + + pub fn as_ref(&self) -> Binder<&T> { + ty::Binder(&self.0) + } + + pub fn map_bound_ref(&self, f: F) -> Binder + where F: FnOnce(&T) -> U + { + self.as_ref().map_bound(f) + } + + pub fn map_bound(self, f: F) -> Binder + where F: FnOnce(T) -> U + { + ty::Binder(f(self.0)) + } } #[derive(Clone, Copy, PartialEq)] @@ -2062,8 +2078,7 @@ impl<'tcx> ToPolyTraitRef<'tcx> for Rc> { impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - // We are just preserving the binder levels here - ty::Binder(self.0.trait_ref.clone()) + self.map_bound_ref(|trait_pred| trait_pred.trait_ref.clone()) } } @@ -6755,6 +6770,30 @@ pub fn binds_late_bound_regions<'tcx, T>( count_late_bound_regions(tcx, value) > 0 } +/// Flattens two binding levels into one. So `for<'a> for<'b> Foo` +/// becomes `for<'a,'b> Foo`. +pub fn flatten_late_bound_regions<'tcx, T>( + tcx: &ty::ctxt<'tcx>, + bound2_value: &Binder>) + -> Binder + where T: TypeFoldable<'tcx> + Repr<'tcx> +{ + let bound0_value = bound2_value.skip_binder().skip_binder(); + let value = ty_fold::fold_regions(tcx, bound0_value, |region, current_depth| { + match region { + ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { + // should be true if no escaping regions from bound2_value + assert!(debruijn.depth - current_depth <= 1); + ty::ReLateBound(DebruijnIndex::new(current_depth), br) + } + _ => { + region + } + } + }); + Binder(value) +} + pub fn no_late_bound_regions<'tcx, T>( tcx: &ty::ctxt<'tcx>, value: &Binder) @@ -7093,6 +7132,12 @@ impl<'tcx> RegionEscape for Predicate<'tcx> { } } +impl<'tcx,P:RegionEscape> RegionEscape for traits::Obligation<'tcx,P> { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.predicate.has_regions_escaping_depth(depth) + } +} + impl<'tcx> RegionEscape for TraitRef<'tcx> { fn has_regions_escaping_depth(&self, depth: u32) -> bool { self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||