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:
bors 2022-06-11 01:39:43 +00:00
commit 75307c22f3
22 changed files with 186 additions and 191 deletions

View file

@ -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,
)
},
);
}

View file

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

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

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

View file

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

View file

@ -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)
}
}

View file

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

View file

@ -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),

View file

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

View file

@ -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![];

View file

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

View file

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

View file

@ -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(),

View file

@ -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),

View file

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

View file

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

View file

@ -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() {

View file

@ -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)
}
}

View file

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

View file

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

View file

@ -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(&lt_name),
},
))
})
.0,
}
),
),
),
];