Auto merge of #97648 - lcnr:bound-var-replacer, r=jackh726
cleanup bound variable handling each commit should be pretty self-contained and hopefully straightforward to review. I've added 677ec23a8dbf8ff5f1c03ccebd46f8b85e5ec1fc so that we can stop returning the region map from `replace_bound_vars_with_fresh_vars` in the following commit. r? `@nikomatsakis` or `@jackh726`
This commit is contained in:
commit
75307c22f3
22 changed files with 186 additions and 191 deletions
|
|
@ -60,13 +60,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// Replace the bound items in the fn sig with fresh
|
||||
// variables, so that they represent the view from
|
||||
// "inside" the closure.
|
||||
self.infcx
|
||||
.replace_bound_vars_with_fresh_vars(
|
||||
body.span,
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
poly_sig,
|
||||
)
|
||||
.0
|
||||
self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
body.span,
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
poly_sig,
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
|||
use rustc_infer::infer::region_constraints::RegionConstraintData;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin,
|
||||
InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
|
||||
};
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||
|
|
@ -1436,11 +1436,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
};
|
||||
let (sig, map) = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
term.source_info.span,
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
sig,
|
||||
);
|
||||
let (sig, map) = tcx.replace_late_bound_regions(sig, |br| {
|
||||
self.infcx.next_region_var(LateBoundRegion(
|
||||
term.source_info.span,
|
||||
br.kind,
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
))
|
||||
});
|
||||
debug!(?sig);
|
||||
let sig = self.normalize(sig, term_location);
|
||||
self.check_call_dest(body, term, &sig, *destination, target, term_location);
|
||||
|
|
|
|||
|
|
@ -86,6 +86,6 @@ where
|
|||
c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
|
||||
};
|
||||
|
||||
tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c)
|
||||
tcx.replace_escaping_bound_vars_uncached(value, fld_r, fld_t, fld_c)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,12 +153,12 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||
{
|
||||
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
|
||||
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
|
||||
self.fields.higher_ranked_sub(b, a, self.a_is_expected)
|
||||
self.fields.higher_ranked_sub(b, a, self.a_is_expected)?;
|
||||
} else {
|
||||
// Fast path for the common case.
|
||||
self.relate(a.skip_binder(), b.skip_binder())?;
|
||||
Ok(a)
|
||||
}
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,78 +3,85 @@
|
|||
|
||||
use super::combine::CombineFields;
|
||||
use super::{HigherRankedType, InferCtxt};
|
||||
|
||||
use crate::infer::CombinedSnapshot;
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Binder, TypeFoldable};
|
||||
|
||||
impl<'a, 'tcx> CombineFields<'a, 'tcx> {
|
||||
/// Checks whether `for<..> sub <: for<..> sup` holds.
|
||||
///
|
||||
/// For this to hold, **all** instantiations of the super type
|
||||
/// have to be a super type of **at least one** instantiation of
|
||||
/// the subtype.
|
||||
///
|
||||
/// This is implemented by first entering a new universe.
|
||||
/// We then replace all bound variables in `sup` with placeholders,
|
||||
/// and all bound variables in `sup` with inference vars.
|
||||
/// We can then just relate the two resulting types as normal.
|
||||
///
|
||||
/// Note: this is a subtle algorithm. For a full explanation, please see
|
||||
/// the [rustc dev guide][rd]
|
||||
///
|
||||
/// [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn higher_ranked_sub<T>(
|
||||
&mut self,
|
||||
a: Binder<'tcx, T>,
|
||||
b: Binder<'tcx, T>,
|
||||
a_is_expected: bool,
|
||||
) -> RelateResult<'tcx, Binder<'tcx, T>>
|
||||
sub: Binder<'tcx, T>,
|
||||
sup: Binder<'tcx, T>,
|
||||
sub_is_expected: bool,
|
||||
) -> RelateResult<'tcx, ()>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
// Rather than checking the subtype relationship between `a` and `b`
|
||||
// as-is, we need to do some extra work here in order to make sure
|
||||
// that function subtyping works correctly with respect to regions
|
||||
//
|
||||
// Note: this is a subtle algorithm. For a full explanation, please see
|
||||
// the rustc dev guide:
|
||||
// <https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html>
|
||||
|
||||
let span = self.trace.cause.span;
|
||||
|
||||
self.infcx.commit_if_ok(|_| {
|
||||
// First, we instantiate each bound region in the supertype with a
|
||||
// fresh placeholder region.
|
||||
let b_prime = self.infcx.replace_bound_vars_with_placeholders(b);
|
||||
// fresh placeholder region. Note that this automatically creates
|
||||
// a new universe if needed.
|
||||
let sup_prime = self.infcx.replace_bound_vars_with_placeholders(sup);
|
||||
|
||||
// Next, we instantiate each bound region in the subtype
|
||||
// with a fresh region variable. These region variables --
|
||||
// but no other pre-existing region variables -- can name
|
||||
// the placeholders.
|
||||
let (a_prime, _) =
|
||||
self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
|
||||
let sub_prime =
|
||||
self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, sub);
|
||||
|
||||
debug!("a_prime={:?}", a_prime);
|
||||
debug!("b_prime={:?}", b_prime);
|
||||
debug!("a_prime={:?}", sub_prime);
|
||||
debug!("b_prime={:?}", sup_prime);
|
||||
|
||||
// Compare types now that bound regions have been replaced.
|
||||
let result = self.sub(a_is_expected).relate(a_prime, b_prime)?;
|
||||
let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?;
|
||||
|
||||
debug!("higher_ranked_sub: OK result={:?}", result);
|
||||
|
||||
// We related `a_prime` and `b_prime`, which just had any bound vars
|
||||
// replaced with placeholders or infer vars, respectively. Relating
|
||||
// them should not introduce new bound vars.
|
||||
Ok(ty::Binder::dummy(result))
|
||||
debug!("higher_ranked_sub: OK result={result:?}");
|
||||
// NOTE: returning the result here would be dangerous as it contains
|
||||
// placeholders which **must not** be named afterwards.
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
/// Replaces all bound variables (lifetimes, types, and constants) bound by
|
||||
/// `binder` with placeholder variables.
|
||||
/// `binder` with placeholder variables in a new universe. This means that the
|
||||
/// new placeholders can only be named by inference variables created after
|
||||
/// this method has been called.
|
||||
///
|
||||
/// This is the first step of checking subtyping when higher-ranked things are involved.
|
||||
/// For more details visit the relevant sections of the [rustc dev guide].
|
||||
///
|
||||
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
T: TypeFoldable<'tcx> + Copy,
|
||||
{
|
||||
// Figure out what the next universe will be, but don't actually create
|
||||
// it until after we've done the substitution (in particular there may
|
||||
// be no bound variables). This is a performance optimization, since the
|
||||
// leak check for example can be skipped if no new universes are created
|
||||
// (i.e., if there are no placeholders).
|
||||
let next_universe = self.universe().next_universe();
|
||||
if let Some(inner) = binder.no_bound_vars() {
|
||||
return inner;
|
||||
}
|
||||
|
||||
let next_universe = self.create_next_universe();
|
||||
|
||||
let fld_r = |br: ty::BoundRegion| {
|
||||
self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
|
||||
|
|
@ -100,23 +107,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
})
|
||||
};
|
||||
|
||||
let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c);
|
||||
|
||||
// If there were higher-ranked regions to replace, then actually create
|
||||
// the next universe (this avoids needlessly creating universes).
|
||||
if !map.is_empty() {
|
||||
let n_u = self.create_next_universe();
|
||||
assert_eq!(n_u, next_universe);
|
||||
}
|
||||
|
||||
debug!(
|
||||
"replace_bound_vars_with_placeholders(\
|
||||
next_universe={:?}, \
|
||||
result={:?}, \
|
||||
map={:?})",
|
||||
next_universe, result, map,
|
||||
);
|
||||
|
||||
let result = self.tcx.replace_bound_vars_uncached(binder, fld_r, fld_t, fld_c);
|
||||
debug!(?next_universe, ?result);
|
||||
result
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ use rustc_span::symbol::Symbol;
|
|||
use rustc_span::Span;
|
||||
|
||||
use std::cell::{Cell, Ref, RefCell};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
|
||||
use self::combine::CombineFields;
|
||||
|
|
@ -1524,25 +1523,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
span: Span,
|
||||
lbrct: LateBoundRegionConversionTime,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
T: TypeFoldable<'tcx> + Copy,
|
||||
{
|
||||
let fld_r =
|
||||
|br: ty::BoundRegion| self.next_region_var(LateBoundRegion(span, br.kind, lbrct));
|
||||
let fld_t = |_| {
|
||||
self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span,
|
||||
if let Some(inner) = value.no_bound_vars() {
|
||||
return inner;
|
||||
}
|
||||
|
||||
let mut region_map = FxHashMap::default();
|
||||
let fld_r = |br: ty::BoundRegion| {
|
||||
*region_map
|
||||
.entry(br)
|
||||
.or_insert_with(|| self.next_region_var(LateBoundRegion(span, br.kind, lbrct)))
|
||||
};
|
||||
|
||||
let mut ty_map = FxHashMap::default();
|
||||
let fld_t = |bt: ty::BoundTy| {
|
||||
*ty_map.entry(bt).or_insert_with(|| {
|
||||
self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span,
|
||||
})
|
||||
})
|
||||
};
|
||||
let fld_c = |_, ty| {
|
||||
self.next_const_var(
|
||||
ty,
|
||||
ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
|
||||
)
|
||||
let mut ct_map = FxHashMap::default();
|
||||
let fld_c = |bc: ty::BoundVar, ty| {
|
||||
*ct_map.entry(bc).or_insert_with(|| {
|
||||
self.next_const_var(
|
||||
ty,
|
||||
ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
|
||||
)
|
||||
})
|
||||
};
|
||||
self.tcx.replace_bound_vars(value, fld_r, fld_t, fld_c)
|
||||
self.tcx.replace_bound_vars_uncached(value, fld_r, fld_t, fld_c)
|
||||
}
|
||||
|
||||
/// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method.
|
||||
|
|
|
|||
|
|
@ -198,7 +198,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
|||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
self.fields.higher_ranked_sub(a, b, self.a_is_expected)
|
||||
self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -656,17 +656,17 @@ struct BoundVarReplacer<'a, 'tcx> {
|
|||
/// the ones we have visited.
|
||||
current_index: ty::DebruijnIndex,
|
||||
|
||||
fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>,
|
||||
fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>,
|
||||
fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>,
|
||||
fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
|
||||
fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
|
||||
fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a),
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> {
|
||||
fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>,
|
||||
fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>,
|
||||
fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>,
|
||||
fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
|
||||
fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
|
||||
fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a),
|
||||
) -> Self {
|
||||
BoundVarReplacer { tcx, current_index: ty::INNERMOST, fld_r, fld_t, fld_c }
|
||||
}
|
||||
|
|
@ -690,55 +690,42 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
|
|||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *t.kind() {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
|
||||
if let Some(fld_t) = self.fld_t.as_mut() {
|
||||
let ty = fld_t(bound_ty);
|
||||
return ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32());
|
||||
}
|
||||
let ty = (self.fld_t)(bound_ty);
|
||||
ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32())
|
||||
}
|
||||
_ if t.has_vars_bound_at_or_above(self.current_index) => {
|
||||
return t.super_fold_with(self);
|
||||
}
|
||||
_ => {}
|
||||
_ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
|
||||
_ => t,
|
||||
}
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
|
||||
if let Some(fld_r) = self.fld_r.as_mut() {
|
||||
let region = fld_r(br);
|
||||
return if let ty::ReLateBound(debruijn1, br) = *region {
|
||||
// If the callback returns a late-bound region,
|
||||
// that region should always use the INNERMOST
|
||||
// debruijn index. Then we adjust it to the
|
||||
// correct depth.
|
||||
assert_eq!(debruijn1, ty::INNERMOST);
|
||||
self.tcx.mk_region(ty::ReLateBound(debruijn, br))
|
||||
} else {
|
||||
region
|
||||
};
|
||||
let region = (self.fld_r)(br);
|
||||
if let ty::ReLateBound(debruijn1, br) = *region {
|
||||
// If the callback returns a late-bound region,
|
||||
// that region should always use the INNERMOST
|
||||
// debruijn index. Then we adjust it to the
|
||||
// correct depth.
|
||||
assert_eq!(debruijn1, ty::INNERMOST);
|
||||
self.tcx.mk_region(ty::ReLateBound(debruijn, br))
|
||||
} else {
|
||||
region
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => r,
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
match ct.val() {
|
||||
ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
|
||||
if let Some(fld_c) = self.fld_c.as_mut() {
|
||||
let ct = fld_c(bound_const, ct.ty());
|
||||
return ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32());
|
||||
}
|
||||
let ct = (self.fld_c)(bound_const, ct.ty());
|
||||
ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32())
|
||||
}
|
||||
_ if ct.has_vars_bound_at_or_above(self.current_index) => {
|
||||
return ct.super_fold_with(self);
|
||||
}
|
||||
_ => {}
|
||||
_ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
|
||||
_ => ct,
|
||||
}
|
||||
ct
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -752,8 +739,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// returned at the end with each bound region and the free region
|
||||
/// that replaced it.
|
||||
///
|
||||
/// This method only replaces late bound regions and the result may still
|
||||
/// contain escaping bound types.
|
||||
/// # Panics
|
||||
///
|
||||
/// This method only replaces late bound regions. Any types or
|
||||
/// constants bound by `value` will cause an ICE.
|
||||
pub fn replace_late_bound_regions<T, F>(
|
||||
self,
|
||||
value: Binder<'tcx, T>,
|
||||
|
|
@ -764,22 +753,35 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
let mut region_map = BTreeMap::new();
|
||||
let mut real_fld_r =
|
||||
|br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
|
||||
let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
|
||||
let value = self.replace_late_bound_regions_uncached(value, real_fld_r);
|
||||
(value, region_map)
|
||||
}
|
||||
|
||||
pub fn replace_late_bound_regions_uncached<T, F>(
|
||||
self,
|
||||
value: Binder<'tcx, T>,
|
||||
mut fld_r: F,
|
||||
) -> T
|
||||
where
|
||||
F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
let mut fld_t = |b| bug!("unexpected bound ty in binder: {b:?}");
|
||||
let mut fld_c = |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}");
|
||||
let value = value.skip_binder();
|
||||
let value = if !value.has_escaping_bound_vars() {
|
||||
if !value.has_escaping_bound_vars() {
|
||||
value
|
||||
} else {
|
||||
let mut replacer = BoundVarReplacer::new(self, Some(&mut real_fld_r), None, None);
|
||||
let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t, &mut fld_c);
|
||||
value.fold_with(&mut replacer)
|
||||
};
|
||||
(value, region_map)
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces all escaping bound vars. The `fld_r` closure replaces escaping
|
||||
/// bound regions; the `fld_t` closure replaces escaping bound types and the `fld_c`
|
||||
/// closure replaces escaping bound consts.
|
||||
pub fn replace_escaping_bound_vars<T, F, G, H>(
|
||||
pub fn replace_escaping_bound_vars_uncached<T, F, G, H>(
|
||||
self,
|
||||
value: T,
|
||||
mut fld_r: F,
|
||||
|
|
@ -795,32 +797,28 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
if !value.has_escaping_bound_vars() {
|
||||
value
|
||||
} else {
|
||||
let mut replacer =
|
||||
BoundVarReplacer::new(self, Some(&mut fld_r), Some(&mut fld_t), Some(&mut fld_c));
|
||||
let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t, &mut fld_c);
|
||||
value.fold_with(&mut replacer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces all types or regions bound by the given `Binder`. The `fld_r`
|
||||
/// closure replaces bound regions while the `fld_t` closure replaces bound
|
||||
/// types.
|
||||
pub fn replace_bound_vars<T, F, G, H>(
|
||||
/// closure replaces bound regions, the `fld_t` closure replaces bound
|
||||
/// types, and `fld_c` replaces bound constants.
|
||||
pub fn replace_bound_vars_uncached<T, F, G, H>(
|
||||
self,
|
||||
value: Binder<'tcx, T>,
|
||||
mut fld_r: F,
|
||||
fld_r: F,
|
||||
fld_t: G,
|
||||
fld_c: H,
|
||||
) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
) -> T
|
||||
where
|
||||
F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
||||
G: FnMut(ty::BoundTy) -> Ty<'tcx>,
|
||||
H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>,
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
let mut region_map = BTreeMap::new();
|
||||
let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
|
||||
let value = self.replace_escaping_bound_vars(value.skip_binder(), real_fld_r, fld_t, fld_c);
|
||||
(value, region_map)
|
||||
self.replace_escaping_bound_vars_uncached(value.skip_binder(), fld_r, fld_t, fld_c)
|
||||
}
|
||||
|
||||
/// Replaces any late-bound regions bound in `value` with
|
||||
|
|
@ -833,20 +831,19 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
self.replace_late_bound_regions(value, |br| {
|
||||
self.replace_late_bound_regions_uncached(value, |br| {
|
||||
self.mk_region(ty::ReFree(ty::FreeRegion {
|
||||
scope: all_outlive_scope,
|
||||
bound_region: br.kind,
|
||||
}))
|
||||
})
|
||||
.0
|
||||
}
|
||||
|
||||
pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
self.replace_escaping_bound_vars(
|
||||
self.replace_escaping_bound_vars_uncached(
|
||||
value,
|
||||
|r| {
|
||||
self.mk_region(ty::ReLateBound(
|
||||
|
|
|
|||
|
|
@ -1536,7 +1536,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
|||
let bound_predicate = predicate.kind();
|
||||
if let ty::PredicateKind::Projection(data) = bound_predicate.skip_binder() {
|
||||
let mut selcx = SelectionContext::new(self);
|
||||
let (data, _) = self.replace_bound_vars_with_fresh_vars(
|
||||
let data = self.replace_bound_vars_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
infer::LateBoundRegionConversionTime::HigherRankedType,
|
||||
bound_predicate.rebind(data),
|
||||
|
|
|
|||
|
|
@ -1920,7 +1920,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
|
|||
let cause = &obligation.cause;
|
||||
let param_env = obligation.param_env;
|
||||
|
||||
let (cache_entry, _) = infcx.replace_bound_vars_with_fresh_vars(
|
||||
let cache_entry = infcx.replace_bound_vars_with_fresh_vars(
|
||||
cause.span,
|
||||
LateBoundRegionConversionTime::HigherRankedType,
|
||||
poly_cache_entry,
|
||||
|
|
|
|||
|
|
@ -421,14 +421,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let object_trait_ref = data.principal().unwrap_or_else(|| {
|
||||
span_bug!(obligation.cause.span, "object candidate with no principal")
|
||||
});
|
||||
let object_trait_ref = self
|
||||
.infcx
|
||||
.replace_bound_vars_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
HigherRankedType,
|
||||
object_trait_ref,
|
||||
)
|
||||
.0;
|
||||
let object_trait_ref = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
HigherRankedType,
|
||||
object_trait_ref,
|
||||
);
|
||||
let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty);
|
||||
|
||||
let mut nested = vec![];
|
||||
|
|
|
|||
|
|
@ -1453,7 +1453,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
potentially_unnormalized_candidates: bool,
|
||||
) -> ProjectionMatchesProjection {
|
||||
let mut nested_obligations = Vec::new();
|
||||
let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
let infer_predicate = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
LateBoundRegionConversionTime::HigherRankedType,
|
||||
env_predicate,
|
||||
|
|
|
|||
|
|
@ -152,13 +152,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// fnmut vs fnonce. If so, we have to defer further processing.
|
||||
if self.closure_kind(substs).is_none() {
|
||||
let closure_sig = substs.as_closure().sig();
|
||||
let closure_sig = self
|
||||
.replace_bound_vars_with_fresh_vars(
|
||||
call_expr.span,
|
||||
infer::FnCall,
|
||||
closure_sig,
|
||||
)
|
||||
.0;
|
||||
let closure_sig = self.replace_bound_vars_with_fresh_vars(
|
||||
call_expr.span,
|
||||
infer::FnCall,
|
||||
closure_sig,
|
||||
);
|
||||
let adjustments = self.adjust_steps(autoderef);
|
||||
self.record_deferred_call_resolution(
|
||||
def_id,
|
||||
|
|
@ -503,8 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// renormalize the associated types at this point, since they
|
||||
// previously appeared within a `Binder<>` and hence would not
|
||||
// have been normalized before.
|
||||
let fn_sig =
|
||||
self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig).0;
|
||||
let fn_sig = self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
|
||||
let fn_sig = self.normalize_associated_types_in(call_expr.span, fn_sig);
|
||||
|
||||
// Call the generic checker.
|
||||
|
|
|
|||
|
|
@ -550,7 +550,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'.
|
||||
) {
|
||||
// Instantiate (this part of..) S to S', i.e., with fresh variables.
|
||||
let (supplied_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
let supplied_ty = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
hir_ty.span,
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
supplied_sig.inputs().rebind(supplied_ty),
|
||||
|
|
@ -563,7 +563,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
all_obligations.extend(obligations);
|
||||
}
|
||||
|
||||
let (supplied_output_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
let supplied_output_ty = self.infcx.replace_bound_vars_with_fresh_vars(
|
||||
decl.output.span(),
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
supplied_sig.output(),
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ fn compare_predicate_entailment<'tcx>(
|
|||
|
||||
let mut wf_tys = FxHashSet::default();
|
||||
|
||||
let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars(
|
||||
let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
|
||||
impl_m_span,
|
||||
infer::HigherRankedType,
|
||||
tcx.fn_sig(impl_m.def_id),
|
||||
|
|
|
|||
|
|
@ -561,13 +561,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// placeholder lifetimes with probing, we just replace higher lifetimes
|
||||
// with fresh vars.
|
||||
let span = args.get(i).map(|a| a.span).unwrap_or(expr.span);
|
||||
let input = self
|
||||
.replace_bound_vars_with_fresh_vars(
|
||||
span,
|
||||
infer::LateBoundRegionConversionTime::FnCall,
|
||||
fn_sig.input(i),
|
||||
)
|
||||
.0;
|
||||
let input = self.replace_bound_vars_with_fresh_vars(
|
||||
span,
|
||||
infer::LateBoundRegionConversionTime::FnCall,
|
||||
fn_sig.input(i),
|
||||
);
|
||||
self.require_type_is_sized_deferred(
|
||||
input,
|
||||
span,
|
||||
|
|
@ -581,13 +579,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Also, as we just want to check sizedness, instead of introducing
|
||||
// placeholder lifetimes with probing, we just replace higher lifetimes
|
||||
// with fresh vars.
|
||||
let output = self
|
||||
.replace_bound_vars_with_fresh_vars(
|
||||
expr.span,
|
||||
infer::LateBoundRegionConversionTime::FnCall,
|
||||
fn_sig.output(),
|
||||
)
|
||||
.0;
|
||||
let output = self.replace_bound_vars_with_fresh_vars(
|
||||
expr.span,
|
||||
infer::LateBoundRegionConversionTime::FnCall,
|
||||
fn_sig.output(),
|
||||
);
|
||||
self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
item_segment: &hir::PathSegment<'_>,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
|
||||
let trait_ref = self.replace_bound_vars_with_fresh_vars(
|
||||
span,
|
||||
infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
|
||||
poly_trait_ref,
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
_ => return false,
|
||||
};
|
||||
|
||||
let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, sig).0;
|
||||
let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, sig);
|
||||
let sig = self.normalize_associated_types_in(expr.span, sig);
|
||||
if self.can_coerce(sig.output(), expected) {
|
||||
let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
|
||||
|
|
|
|||
|
|
@ -572,8 +572,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
|
||||
fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
T: TypeFoldable<'tcx> + Copy,
|
||||
{
|
||||
self.fcx.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, value).0
|
||||
self.fcx.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, value)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// may reference those regions.
|
||||
let fn_sig = tcx.bound_fn_sig(def_id);
|
||||
let fn_sig = fn_sig.subst(self.tcx, substs);
|
||||
let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
|
||||
let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);
|
||||
|
||||
let InferOk { value, obligations: o } = if is_op {
|
||||
self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr)
|
||||
|
|
|
|||
|
|
@ -905,7 +905,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
self.probe(|_| {
|
||||
let substs = self.fresh_substs_for_item(self.span, method.def_id);
|
||||
let fty = fty.subst(self.tcx, substs);
|
||||
let (fty, _) =
|
||||
let fty =
|
||||
self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty);
|
||||
|
||||
if let Some(self_ty) = self_ty {
|
||||
|
|
|
|||
|
|
@ -449,8 +449,9 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
|
|||
format!(
|
||||
"{}::",
|
||||
// Replace the existing lifetimes with a new named lifetime.
|
||||
self.tcx
|
||||
.replace_late_bound_regions(poly_trait_ref, |_| {
|
||||
self.tcx.replace_late_bound_regions_uncached(
|
||||
poly_trait_ref,
|
||||
|_| {
|
||||
self.tcx.mk_region(ty::ReEarlyBound(
|
||||
ty::EarlyBoundRegion {
|
||||
def_id: item_def_id,
|
||||
|
|
@ -458,8 +459,8 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
|
|||
name: Symbol::intern(<_name),
|
||||
},
|
||||
))
|
||||
})
|
||||
.0,
|
||||
}
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue