Refactor how binders are handled in trait selection

This commit is contained in:
Niko Matsakis 2015-03-26 15:53:00 -04:00
parent c59fe8bde2
commit 703308db4a
3 changed files with 212 additions and 127 deletions

View File

@ -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;

View File

@ -172,7 +172,7 @@ struct SelectionCandidateSet<'tcx> {
}
enum BuiltinBoundConditions<'tcx> {
If(Vec<Ty<'tcx>>),
If(ty::Binder<Vec<Ty<'tcx>>>),
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<T>
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<Ty<'tcx>>)
-> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>> {
Ok(If(ty::Binder(v)))
}
fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound,
types: Vec<Ty<'tcx>>)
-> Result<BuiltinBoundConditions<'tcx>, 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<Ty<'tcx>>) -> Vec<PredicateObligation<'tcx>> {
types: ty::Binder<Vec<Ty<'tcx>>>)
-> Vec<PredicateObligation<'tcx>>
{
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<ty::Binder<Ty<'tcx>>> =
types.skip_binder()
.iter()
.map(|&nested_ty| ty::Binder(nested_ty))
.collect();
// For each type, produce a vector of resulting obligations
let obligations: Result<Vec<Vec<_>>, _> = 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::<Result<Vec<PredicateObligation<'tcx>>, _>>();
}).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<Ty<'tcx>>)
nested: ty::Binder<Vec<Ty<'tcx>>>)
-> VtableBuiltinData<PredicateObligation<'tcx>>
{
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<Ty<'tcx>>)
nested: ty::Binder<Vec<Ty<'tcx>>>)
-> VtableDefaultImplData<PredicateObligation<'tcx>>
{
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<VecPerParamSpace<_>,()> = 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<PredicateObligation<'tcx>>
{
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);

View File

@ -1108,16 +1108,16 @@ pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
impl<'tcx> PolyFnSig<'tcx> {
pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
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<'tcx>> {
ty::Binder(self.0.inputs[index])
self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
}
pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
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<T> Binder<T> {
pub fn skip_binder(&self) -> &T {
&self.0
}
pub fn as_ref(&self) -> Binder<&T> {
ty::Binder(&self.0)
}
pub fn map_bound_ref<F,U>(&self, f: F) -> Binder<U>
where F: FnOnce(&T) -> U
{
self.as_ref().map_bound(f)
}
pub fn map_bound<F,U>(self, f: F) -> Binder<U>
where F: FnOnce(T) -> U
{
ty::Binder(f(self.0))
}
}
#[derive(Clone, Copy, PartialEq)]
@ -2062,8 +2078,7 @@ impl<'tcx> ToPolyTraitRef<'tcx> for Rc<TraitRef<'tcx>> {
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<T>>)
-> Binder<T>
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<T>)
@ -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)) ||