universe transition
Remove the leak-check and its associated machinery. Replace with making the solver aware of universes.
This commit is contained in:
parent
eba2ae526b
commit
b68fad670b
@ -1,31 +1,23 @@
|
||||
//! Helper routines for higher-ranked things. See the `doc` module at
|
||||
//! the end of the file for details.
|
||||
|
||||
use super::{CombinedSnapshot,
|
||||
InferCtxt,
|
||||
HigherRankedType,
|
||||
SubregionOrigin,
|
||||
PlaceholderMap};
|
||||
use super::combine::CombineFields;
|
||||
use super::region_constraints::{TaintDirections};
|
||||
use super::{HigherRankedType, InferCtxt, PlaceholderMap};
|
||||
|
||||
use ty::{self, TyCtxt, Binder, TypeFoldable};
|
||||
use ty::error::TypeError;
|
||||
use ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use syntax_pos::Span;
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
||||
pub struct HrMatchResult<U> {
|
||||
pub value: U,
|
||||
}
|
||||
use ty::{self, Binder, TypeFoldable};
|
||||
|
||||
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
pub fn higher_ranked_sub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
|
||||
-> RelateResult<'tcx, Binder<T>>
|
||||
where T: Relate<'tcx>
|
||||
pub fn higher_ranked_sub<T>(
|
||||
&mut self,
|
||||
a: &Binder<T>,
|
||||
b: &Binder<T>,
|
||||
a_is_expected: bool,
|
||||
) -> RelateResult<'tcx, Binder<T>>
|
||||
where
|
||||
T: Relate<'tcx>,
|
||||
{
|
||||
debug!("higher_ranked_sub(a={:?}, b={:?})",
|
||||
a, b);
|
||||
debug!("higher_ranked_sub(a={:?}, b={:?})", a, b);
|
||||
|
||||
// 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
|
||||
@ -35,279 +27,37 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
|
||||
// please see the large comment at the end of the file in the (inlined) module
|
||||
// `doc`.
|
||||
|
||||
// Start a snapshot so we can examine "all bindings that were
|
||||
// created as part of this type comparison".
|
||||
return self.infcx.commit_if_ok(|snapshot| {
|
||||
let span = self.trace.cause.span;
|
||||
let span = self.trace.cause.span;
|
||||
|
||||
// First, we instantiate each bound region in the supertype with a
|
||||
// fresh placeholder region.
|
||||
let (b_prime, placeholder_map) =
|
||||
self.infcx.replace_bound_vars_with_placeholders(b);
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
);
|
||||
// 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);
|
||||
|
||||
debug!("a_prime={:?}", a_prime);
|
||||
debug!("b_prime={:?}", b_prime);
|
||||
debug!("a_prime={:?}", a_prime);
|
||||
debug!("b_prime={:?}", b_prime);
|
||||
|
||||
// Compare types now that bound regions have been replaced.
|
||||
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
|
||||
// Compare types now that bound regions have been replaced.
|
||||
let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
|
||||
|
||||
// Presuming type comparison succeeds, we need to check
|
||||
// that the placeholder regions do not "leak".
|
||||
self.infcx.leak_check(!a_is_expected, span, &placeholder_map, snapshot)?;
|
||||
debug!("higher_ranked_sub: OK result={:?}", result);
|
||||
|
||||
// We are finished with the placeholder regions now so pop
|
||||
// them off.
|
||||
self.infcx.pop_placeholders(placeholder_map, snapshot);
|
||||
|
||||
debug!("higher_ranked_sub: OK result={:?}", result);
|
||||
|
||||
Ok(ty::Binder::bind(result))
|
||||
});
|
||||
Ok(ty::Binder::bind(result))
|
||||
}
|
||||
|
||||
/// The value consists of a pair `(t, u)` where `t` is the
|
||||
/// *matcher* and `u` is a *value*. The idea is to find a
|
||||
/// substitution `S` such that `S(t) == b`, and then return
|
||||
/// `S(u)`. In other words, find values for the late-bound regions
|
||||
/// in `a` that can make `t == b` and then replace the LBR in `u`
|
||||
/// with those values.
|
||||
///
|
||||
/// This routine is (as of this writing) used in trait matching,
|
||||
/// particularly projection.
|
||||
///
|
||||
/// NB. It should not happen that there are LBR appearing in `U`
|
||||
/// that do not appear in `T`. If that happens, those regions are
|
||||
/// unconstrained, and this routine replaces them with `'static`.
|
||||
pub fn higher_ranked_match<T, U>(&mut self,
|
||||
a_pair: &Binder<(T, U)>,
|
||||
b_match: &T,
|
||||
a_is_expected: bool)
|
||||
-> RelateResult<'tcx, HrMatchResult<U>>
|
||||
where T: Relate<'tcx>,
|
||||
U: TypeFoldable<'tcx>
|
||||
{
|
||||
debug!("higher_ranked_match(a={:?}, b={:?})",
|
||||
a_pair, b_match);
|
||||
|
||||
// Start a snapshot so we can examine "all bindings that were
|
||||
// created as part of this type comparison".
|
||||
return self.infcx.commit_if_ok(|snapshot| {
|
||||
// First, we instantiate each bound region in the matcher
|
||||
// with a placeholder region.
|
||||
let ((a_match, a_value), placeholder_map) =
|
||||
self.infcx.replace_bound_vars_with_placeholders(a_pair);
|
||||
|
||||
debug!("higher_ranked_match: a_match={:?}", a_match);
|
||||
debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map);
|
||||
|
||||
// Equate types now that bound regions have been replaced.
|
||||
self.equate(a_is_expected).relate(&a_match, &b_match)?;
|
||||
|
||||
// Map each placeholder region to a vector of other regions that it
|
||||
// must be equated with. (Note that this vector may include other
|
||||
// placeholder regions from `placeholder_map`.)
|
||||
let placeholder_resolution_map: FxHashMap<_, _> =
|
||||
placeholder_map
|
||||
.iter()
|
||||
.map(|(&br, &placeholder)| {
|
||||
let tainted_regions =
|
||||
self.infcx.tainted_regions(snapshot,
|
||||
placeholder,
|
||||
TaintDirections::incoming()); // [1]
|
||||
|
||||
// [1] this routine executes after the placeholder
|
||||
// regions have been *equated* with something
|
||||
// else, so examining the incoming edges ought to
|
||||
// be enough to collect all constraints
|
||||
|
||||
(placeholder, (br, tainted_regions))
|
||||
})
|
||||
.collect();
|
||||
|
||||
// For each placeholder region, pick a representative -- which can
|
||||
// be any region from the sets above, except for other members of
|
||||
// `placeholder_map`. There should always be a representative if things
|
||||
// are properly well-formed.
|
||||
let placeholder_representatives: FxHashMap<_, _> =
|
||||
placeholder_resolution_map
|
||||
.iter()
|
||||
.map(|(&placeholder, &(_, ref regions))| {
|
||||
let representative =
|
||||
regions.iter()
|
||||
.filter(|&&r| !placeholder_resolution_map.contains_key(r))
|
||||
.cloned()
|
||||
.next()
|
||||
.unwrap_or_else(|| {
|
||||
bug!("no representative region for `{:?}` in `{:?}`",
|
||||
placeholder, regions)
|
||||
});
|
||||
|
||||
(placeholder, representative)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Equate all the members of each placeholder set with the
|
||||
// representative.
|
||||
for (placeholder, &(_br, ref regions)) in &placeholder_resolution_map {
|
||||
let representative = &placeholder_representatives[placeholder];
|
||||
debug!("higher_ranked_match: \
|
||||
placeholder={:?} representative={:?} regions={:?}",
|
||||
placeholder, representative, regions);
|
||||
for region in regions.iter()
|
||||
.filter(|&r| !placeholder_resolution_map.contains_key(r))
|
||||
.filter(|&r| r != representative)
|
||||
{
|
||||
let origin = SubregionOrigin::Subtype(self.trace.clone());
|
||||
self.infcx.borrow_region_constraints()
|
||||
.make_eqregion(origin,
|
||||
*representative,
|
||||
*region);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the placeholder regions appearing in value with
|
||||
// their representatives
|
||||
let a_value =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&a_value,
|
||||
|r, _| placeholder_representatives.get(&r).cloned().unwrap_or(r));
|
||||
|
||||
debug!("higher_ranked_match: value={:?}", a_value);
|
||||
|
||||
// We are now done with these placeholder variables.
|
||||
self.infcx.pop_placeholders(placeholder_map, snapshot);
|
||||
|
||||
Ok(HrMatchResult { value: a_value })
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
unbound_value: &T,
|
||||
mut fldr: F)
|
||||
-> T
|
||||
where T: TypeFoldable<'tcx>,
|
||||
F: FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
|
||||
{
|
||||
tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
|
||||
// we should only be encountering "escaping" late-bound regions here,
|
||||
// because the ones at the current level should have been replaced
|
||||
// with fresh variables
|
||||
assert!(match *region {
|
||||
ty::ReLateBound(..) => false,
|
||||
_ => true
|
||||
});
|
||||
|
||||
fldr(region, current_depth)
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
fn tainted_regions(&self,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>,
|
||||
r: ty::Region<'tcx>,
|
||||
directions: TaintDirections)
|
||||
-> FxHashSet<ty::Region<'tcx>> {
|
||||
self.borrow_region_constraints().tainted(
|
||||
self.tcx,
|
||||
&snapshot.region_constraints_snapshot,
|
||||
r,
|
||||
directions)
|
||||
}
|
||||
|
||||
fn region_vars_confined_to_snapshot(&self,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>)
|
||||
-> Vec<ty::RegionVid>
|
||||
{
|
||||
/*!
|
||||
* Returns the set of region variables that do not affect any
|
||||
* types/regions which existed before `snapshot` was
|
||||
* started. This is used in the sub/lub/glb computations. The
|
||||
* idea here is that when we are computing lub/glb of two
|
||||
* regions, we sometimes create intermediate region variables.
|
||||
* Those region variables may touch some of the placeholder or
|
||||
* other "forbidden" regions we created to replace bound
|
||||
* regions, but they don't really represent an "external"
|
||||
* constraint.
|
||||
*
|
||||
* However, sometimes fresh variables are created for other
|
||||
* purposes too, and those *may* represent an external
|
||||
* constraint. In particular, when a type variable is
|
||||
* instantiated, we create region variables for all the
|
||||
* regions that appear within, and if that type variable
|
||||
* pre-existed the snapshot, then those region variables
|
||||
* represent external constraints.
|
||||
*
|
||||
* An example appears in the unit test
|
||||
* `sub_free_bound_false_infer`. In this test, we want to
|
||||
* know whether
|
||||
*
|
||||
* ```rust
|
||||
* fn(_#0t) <: for<'a> fn(&'a int)
|
||||
* ```
|
||||
*
|
||||
* Note that the subtype has a type variable. Because the type
|
||||
* variable can't be instantiated with a region that is bound
|
||||
* in the fn signature, this comparison ought to fail. But if
|
||||
* we're not careful, it will succeed.
|
||||
*
|
||||
* The reason is that when we walk through the subtyping
|
||||
* algorithm, we begin by replacing `'a` with a placeholder
|
||||
* variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
|
||||
* can be made true by unifying `_#0t` with `&'1 int`. In the
|
||||
* process, we create a fresh variable for the placeholder
|
||||
* region, `'$2`, and hence we have that `_#0t == &'$2
|
||||
* int`. However, because `'$2` was created during the sub
|
||||
* computation, if we're not careful we will erroneously
|
||||
* assume it is one of the transient region variables
|
||||
* representing a lub/glb internally. Not good.
|
||||
*
|
||||
* To prevent this, we check for type variables which were
|
||||
* unified during the snapshot, and say that any region
|
||||
* variable created during the snapshot but which finds its
|
||||
* way into a type variable is considered to "escape" the
|
||||
* snapshot.
|
||||
*/
|
||||
|
||||
let mut region_vars =
|
||||
self.borrow_region_constraints().vars_created_since_snapshot(
|
||||
&snapshot.region_constraints_snapshot);
|
||||
|
||||
let escaping_types =
|
||||
self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot);
|
||||
|
||||
let mut escaping_region_vars = FxHashSet::default();
|
||||
for ty in &escaping_types {
|
||||
self.tcx.collect_regions(ty, &mut escaping_region_vars);
|
||||
}
|
||||
|
||||
region_vars.retain(|®ion_vid| {
|
||||
let r = ty::ReVar(region_vid);
|
||||
!escaping_region_vars.contains(&r)
|
||||
});
|
||||
|
||||
debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}",
|
||||
region_vars,
|
||||
escaping_types);
|
||||
|
||||
region_vars
|
||||
}
|
||||
|
||||
/// Replace all regions (resp. types) bound by `binder` with placeholder
|
||||
/// regions (resp. types) and return a map indicating which bound-region
|
||||
/// was replaced with what placeholder region. This is the first step of
|
||||
/// checking subtyping when higher-ranked things are involved.
|
||||
/// placeholder region. This is the first step of checking subtyping
|
||||
/// when higher-ranked things are involved.
|
||||
///
|
||||
/// **Important:** you must call this function from within a snapshot.
|
||||
/// Moreover, before committing the snapshot, you must eventually call
|
||||
@ -354,201 +104,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
(result, map)
|
||||
}
|
||||
|
||||
/// Searches the region constraints created since `snapshot` was started
|
||||
/// and checks to determine whether any of the placeholder regions created
|
||||
/// in `placeholder_map` would "escape" -- meaning that they are related to
|
||||
/// other regions in some way. If so, the higher-ranked subtyping doesn't
|
||||
/// hold. See `README.md` for more details.
|
||||
pub fn leak_check(&self,
|
||||
overly_polymorphic: bool,
|
||||
_span: Span,
|
||||
placeholder_map: &PlaceholderMap<'tcx>,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>)
|
||||
-> RelateResult<'tcx, ()>
|
||||
{
|
||||
debug!("leak_check: placeholder_map={:?}",
|
||||
placeholder_map);
|
||||
|
||||
// If the user gave `-Zno-leak-check`, then skip the leak
|
||||
// check completely. This is wildly unsound and also not
|
||||
// unlikely to cause an ICE or two. It is intended for use
|
||||
// only during a transition period, in which the MIR typeck
|
||||
// uses the "universe-style" check, and the rest of typeck
|
||||
// uses the more conservative leak check. Since the leak
|
||||
// check is more conservative, we can't test the
|
||||
// universe-style check without disabling it.
|
||||
if self.tcx.sess.opts.debugging_opts.no_leak_check {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let new_vars = self.region_vars_confined_to_snapshot(snapshot);
|
||||
for (&placeholder_br, &placeholder) in placeholder_map {
|
||||
// The inputs to a placeholder variable can only
|
||||
// be itself or other new variables.
|
||||
let incoming_taints = self.tainted_regions(snapshot,
|
||||
placeholder,
|
||||
TaintDirections::both());
|
||||
for &tainted_region in &incoming_taints {
|
||||
// Each placeholder should only be relatable to itself
|
||||
// or new variables:
|
||||
match *tainted_region {
|
||||
ty::ReVar(vid) => {
|
||||
if new_vars.contains(&vid) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if tainted_region == placeholder { continue; }
|
||||
}
|
||||
};
|
||||
|
||||
debug!("{:?} (which replaced {:?}) is tainted by {:?}",
|
||||
placeholder,
|
||||
placeholder_br,
|
||||
tainted_region);
|
||||
|
||||
return Err(if overly_polymorphic {
|
||||
debug!("Overly polymorphic!");
|
||||
TypeError::RegionsOverlyPolymorphic(placeholder_br, tainted_region)
|
||||
} else {
|
||||
debug!("Not as polymorphic!");
|
||||
TypeError::RegionsInsufficientlyPolymorphic(placeholder_br, tainted_region)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This code converts from placeholder regions back to late-bound
|
||||
/// regions. It works by replacing each region in the taint set of a
|
||||
/// placeholder region with a bound-region. The bound region will be bound
|
||||
/// by the outer-most binder in `value`; the caller must ensure that there is
|
||||
/// such a binder and it is the right place.
|
||||
///
|
||||
/// This routine is only intended to be used when the leak-check has
|
||||
/// passed; currently, it's used in the trait matching code to create
|
||||
/// a set of nested obligations from an impl that matches against
|
||||
/// something higher-ranked. More details can be found in
|
||||
/// `librustc/middle/traits/README.md`.
|
||||
///
|
||||
/// As a brief example, consider the obligation `for<'a> Fn(&'a int)
|
||||
/// -> &'a int`, and the impl:
|
||||
///
|
||||
/// impl<A,R> Fn<A,R> for SomethingOrOther
|
||||
/// where A : Clone
|
||||
/// { ... }
|
||||
///
|
||||
/// Here we will have replaced `'a` with a placeholder region
|
||||
/// `'0`. This means that our substitution will be `{A=>&'0
|
||||
/// int, R=>&'0 int}`.
|
||||
///
|
||||
/// When we apply the substitution to the bounds, we will wind up with
|
||||
/// `&'0 int : Clone` as a predicate. As a last step, we then go and
|
||||
/// replace `'0` with a late-bound region `'a`. The depth is matched
|
||||
/// to the depth of the predicate, in this case 1, so that the final
|
||||
/// predicate is `for<'a> &'a int : Clone`.
|
||||
pub fn plug_leaks<T>(&self,
|
||||
placeholder_map: PlaceholderMap<'tcx>,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>,
|
||||
value: T) -> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
debug!("plug_leaks(placeholder_map={:?}, value={:?})",
|
||||
placeholder_map,
|
||||
value);
|
||||
|
||||
if placeholder_map.is_empty() {
|
||||
return value;
|
||||
}
|
||||
|
||||
// Compute a mapping from the "taint set" of each placeholder
|
||||
// region back to the `ty::BoundRegion` that it originally
|
||||
// represented. Because `leak_check` passed, we know that
|
||||
// these taint sets are mutually disjoint.
|
||||
let inv_placeholder_map: FxHashMap<ty::Region<'tcx>, ty::BoundRegion> =
|
||||
placeholder_map
|
||||
.iter()
|
||||
.flat_map(|(&placeholder_br, &placeholder)| {
|
||||
self.tainted_regions(snapshot, placeholder, TaintDirections::both())
|
||||
.into_iter()
|
||||
.map(move |tainted_region| (tainted_region, placeholder_br))
|
||||
})
|
||||
.collect();
|
||||
|
||||
debug!("plug_leaks: inv_placeholder_map={:?}",
|
||||
inv_placeholder_map);
|
||||
|
||||
// Remove any instantiated type variables from `value`; those can hide
|
||||
// references to regions from the `fold_regions` code below.
|
||||
let value = self.resolve_type_vars_if_possible(&value);
|
||||
|
||||
// Map any placeholder byproducts back to a late-bound
|
||||
// region. Put that late-bound region at whatever the outermost
|
||||
// binder is that we encountered in `value`. The caller is
|
||||
// responsible for ensuring that (a) `value` contains at least one
|
||||
// binder and (b) that binder is the one we want to use.
|
||||
let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| {
|
||||
match inv_placeholder_map.get(&r) {
|
||||
None => r,
|
||||
Some(br) => {
|
||||
// It is the responsibility of the caller to ensure
|
||||
// that each placeholder region appears within a
|
||||
// binder. In practice, this routine is only used by
|
||||
// trait checking, and all of the placeholder regions
|
||||
// appear inside predicates, which always have
|
||||
// binders, so this assert is satisfied.
|
||||
assert!(current_depth > ty::INNERMOST);
|
||||
|
||||
// since leak-check passed, this placeholder region
|
||||
// should only have incoming edges from variables
|
||||
// (which ought not to escape the snapshot, but we
|
||||
// don't check that) or itself
|
||||
assert!(
|
||||
match *r {
|
||||
ty::ReVar(_) => true,
|
||||
ty::RePlaceholder(index) => index.name == *br,
|
||||
_ => false,
|
||||
},
|
||||
"leak-check would have us replace {:?} with {:?}",
|
||||
r, br);
|
||||
|
||||
self.tcx.mk_region(ty::ReLateBound(
|
||||
current_depth.shifted_out(1),
|
||||
br.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
self.pop_placeholders(placeholder_map, snapshot);
|
||||
|
||||
debug!("plug_leaks: result={:?}", result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Pops the placeholder regions found in `placeholder_map` from the region
|
||||
/// inference context. Whenever you create placeholder regions via
|
||||
/// `replace_bound_vars_with_placeholders`, they must be popped before you
|
||||
/// commit the enclosing snapshot (if you do not commit, e.g., within a
|
||||
/// probe or as a result of an error, then this is not necessary, as
|
||||
/// popping happens as part of the rollback).
|
||||
///
|
||||
/// Note: popping also occurs implicitly as part of `leak_check`.
|
||||
pub fn pop_placeholders(
|
||||
&self,
|
||||
placeholder_map: PlaceholderMap<'tcx>,
|
||||
snapshot: &CombinedSnapshot<'a, 'tcx>,
|
||||
) {
|
||||
debug!("pop_placeholders({:?})", placeholder_map);
|
||||
let placeholder_regions: FxHashSet<_> = placeholder_map.values().cloned().collect();
|
||||
self.borrow_region_constraints().pop_placeholders(&placeholder_regions);
|
||||
self.universe.set(snapshot.universe);
|
||||
if !placeholder_map.is_empty() {
|
||||
self.projection_cache.borrow_mut().rollback_placeholder(
|
||||
&snapshot.projection_cache_snapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,23 +215,41 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
) -> bool {
|
||||
debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
|
||||
|
||||
// Check if this relationship is implied by a given.
|
||||
match *a_region {
|
||||
// Check if this relationship is implied by a given.
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid))
|
||||
{
|
||||
debug!("given");
|
||||
return false;
|
||||
},
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
||||
match *b_data {
|
||||
VarValue::Value(cur_region) => {
|
||||
let lub = self.lub_concrete_regions(a_region, cur_region);
|
||||
let mut lub = self.lub_concrete_regions(a_region, cur_region);
|
||||
if lub == cur_region {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Watch out for `'b: !1` relationships, where the
|
||||
// universe of `'b` can't name the placeholder `!1`. In
|
||||
// that case, we have to grow `'b` to be `'static` for the
|
||||
// relationship to hold. This is obviously a kind of sub-optimal
|
||||
// choice -- in the future, when we incorporate a knowledge
|
||||
// of the parameter environment, we might be able to find a
|
||||
// tighter bound than `'static`.
|
||||
//
|
||||
// (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
|
||||
let b_universe = self.var_infos[b_vid].universe;
|
||||
if let ty::RePlaceholder(p) = lub {
|
||||
if b_universe.cannot_name(p.universe) {
|
||||
lub = self.tcx().types.re_static;
|
||||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
"Expanding value of {:?} from {:?} to {:?}",
|
||||
b_vid, cur_region, lub
|
||||
@ -554,10 +572,22 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
lower_bounds.sort_by_key(region_order_key);
|
||||
upper_bounds.sort_by_key(region_order_key);
|
||||
|
||||
let node_universe = self.var_infos[node_idx].universe;
|
||||
|
||||
for lower_bound in &lower_bounds {
|
||||
let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region {
|
||||
if node_universe.cannot_name(p.universe) {
|
||||
self.tcx().types.re_static
|
||||
} else {
|
||||
lower_bound.region
|
||||
}
|
||||
} else {
|
||||
lower_bound.region
|
||||
};
|
||||
|
||||
for upper_bound in &upper_bounds {
|
||||
if !self.region_rels
|
||||
.is_subregion_of(lower_bound.region, upper_bound.region)
|
||||
.is_subregion_of(effective_lower_bound, upper_bound.region)
|
||||
{
|
||||
let origin = self.var_infos[node_idx].origin.clone();
|
||||
debug!(
|
||||
@ -580,9 +610,10 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
span_bug!(
|
||||
self.var_infos[node_idx].origin.span(),
|
||||
"collect_error_for_expanding_node() could not find \
|
||||
error for var {:?}, lower_bounds={:?}, \
|
||||
upper_bounds={:?}",
|
||||
error for var {:?} in universe {:?}, lower_bounds={:#?}, \
|
||||
upper_bounds={:#?}",
|
||||
node_idx,
|
||||
node_universe,
|
||||
lower_bounds,
|
||||
upper_bounds
|
||||
);
|
||||
|
@ -32,7 +32,6 @@ use ty::{FloatVid, IntVid, TyVid};
|
||||
use util::nodemap::FxHashMap;
|
||||
|
||||
use self::combine::CombineFields;
|
||||
use self::higher_ranked::HrMatchResult;
|
||||
use self::lexical_region_resolve::LexicalRegionResolutions;
|
||||
use self::outlives::env::OutlivesEnvironment;
|
||||
use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
|
||||
@ -948,39 +947,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(self.commit_if_ok(|snapshot| {
|
||||
let (
|
||||
ty::SubtypePredicate {
|
||||
a_is_expected,
|
||||
a,
|
||||
b,
|
||||
},
|
||||
placeholder_map,
|
||||
) = self.replace_bound_vars_with_placeholders(predicate);
|
||||
let (
|
||||
ty::SubtypePredicate {
|
||||
a_is_expected,
|
||||
a,
|
||||
b,
|
||||
},
|
||||
_,
|
||||
) = self.replace_bound_vars_with_placeholders(predicate);
|
||||
|
||||
let cause_span = cause.span;
|
||||
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
|
||||
self.leak_check(false, cause_span, &placeholder_map, snapshot)?;
|
||||
self.pop_placeholders(placeholder_map, snapshot);
|
||||
Ok(ok.unit())
|
||||
}))
|
||||
Some(
|
||||
self.at(cause, param_env)
|
||||
.sub_exp(a_is_expected, a, b)
|
||||
.map(|ok| ok.unit()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn region_outlives_predicate(
|
||||
&self,
|
||||
cause: &traits::ObligationCause<'tcx>,
|
||||
predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
|
||||
) -> UnitResult<'tcx> {
|
||||
self.commit_if_ok(|snapshot| {
|
||||
let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
|
||||
self.replace_bound_vars_with_placeholders(predicate);
|
||||
let origin = SubregionOrigin::from_obligation_cause(cause, || {
|
||||
RelateRegionParamBound(cause.span)
|
||||
});
|
||||
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
|
||||
self.leak_check(false, cause.span, &placeholder_map, snapshot)?;
|
||||
Ok(self.pop_placeholders(placeholder_map, snapshot))
|
||||
})
|
||||
) {
|
||||
let (ty::OutlivesPredicate(r_a, r_b), _) =
|
||||
self.replace_bound_vars_with_placeholders(predicate);
|
||||
let origin =
|
||||
SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
|
||||
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
|
||||
}
|
||||
|
||||
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
|
||||
@ -1389,46 +1381,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
self.tcx.replace_bound_vars(value, fld_r, fld_t)
|
||||
}
|
||||
|
||||
/// Given a higher-ranked projection predicate like:
|
||||
///
|
||||
/// for<'a> <T as Fn<&'a u32>>::Output = &'a u32
|
||||
///
|
||||
/// and a target trait-ref like:
|
||||
///
|
||||
/// <T as Fn<&'x u32>>
|
||||
///
|
||||
/// find a substitution `S` for the higher-ranked regions (here,
|
||||
/// `['a => 'x]`) such that the predicate matches the trait-ref,
|
||||
/// and then return the value (here, `&'a u32`) but with the
|
||||
/// substitution applied (hence, `&'x u32`).
|
||||
///
|
||||
/// See `higher_ranked_match` in `higher_ranked/mod.rs` for more
|
||||
/// details.
|
||||
pub fn match_poly_projection_predicate(
|
||||
&self,
|
||||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
match_a: ty::PolyProjectionPredicate<'tcx>,
|
||||
match_b: ty::TraitRef<'tcx>,
|
||||
) -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>> {
|
||||
let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty));
|
||||
let trace = TypeTrace {
|
||||
cause,
|
||||
values: TraitRefs(ExpectedFound::new(
|
||||
true,
|
||||
match_pair.skip_binder().0,
|
||||
match_b,
|
||||
)),
|
||||
};
|
||||
|
||||
let mut combine = self.combine_fields(trace, param_env);
|
||||
let result = combine.higher_ranked_match(&match_pair, &match_b, true)?;
|
||||
Ok(InferOk {
|
||||
value: result,
|
||||
obligations: combine.obligations,
|
||||
})
|
||||
}
|
||||
|
||||
/// See `verify_generic_bound` method in `region_constraints`
|
||||
pub fn verify_generic_bound(
|
||||
&self,
|
||||
|
@ -17,8 +17,6 @@ use ty::{Region, RegionVid};
|
||||
use std::collections::BTreeMap;
|
||||
use std::{cmp, fmt, mem, u32};
|
||||
|
||||
mod taint;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RegionConstraintCollector<'tcx> {
|
||||
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
|
||||
@ -826,35 +824,6 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Computes all regions that have been related to `r0` since the
|
||||
/// mark `mark` was made---`r0` itself will be the first
|
||||
/// entry. The `directions` parameter controls what kind of
|
||||
/// relations are considered. For example, one can say that only
|
||||
/// "incoming" edges to `r0` are desired, in which case one will
|
||||
/// get the set of regions `{r|r <= r0}`. This is used when
|
||||
/// checking whether placeholder regions are being improperly
|
||||
/// related to other regions.
|
||||
pub fn tainted(
|
||||
&self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
mark: &RegionSnapshot,
|
||||
r0: Region<'tcx>,
|
||||
directions: TaintDirections,
|
||||
) -> FxHashSet<ty::Region<'tcx>> {
|
||||
debug!(
|
||||
"tainted(mark={:?}, r0={:?}, directions={:?})",
|
||||
mark, r0, directions
|
||||
);
|
||||
|
||||
// `result_set` acts as a worklist: we explore all outgoing
|
||||
// edges and add any new regions we find to result_set. This
|
||||
// is not a terribly efficient implementation.
|
||||
let mut taint_set = taint::TaintSet::new(directions, r0);
|
||||
taint_set.fixed_point(tcx, &self.undo_log[mark.length..], &self.data.verifys);
|
||||
debug!("tainted: result={:?}", taint_set);
|
||||
return taint_set.into_set();
|
||||
}
|
||||
|
||||
pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> bool {
|
||||
self.undo_log[mark.length..]
|
||||
.iter()
|
||||
|
@ -1,85 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct TaintSet<'tcx> {
|
||||
directions: TaintDirections,
|
||||
regions: FxHashSet<ty::Region<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TaintSet<'tcx> {
|
||||
pub(super) fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
|
||||
let mut regions = FxHashSet::default();
|
||||
regions.insert(initial_region);
|
||||
TaintSet {
|
||||
directions: directions,
|
||||
regions: regions,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn fixed_point(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'_, '_, 'tcx>,
|
||||
undo_log: &[UndoLog<'tcx>],
|
||||
verifys: &[Verify<'tcx>],
|
||||
) {
|
||||
let mut prev_len = 0;
|
||||
while prev_len < self.len() {
|
||||
debug!(
|
||||
"tainted: prev_len = {:?} new_len = {:?}",
|
||||
prev_len,
|
||||
self.len()
|
||||
);
|
||||
|
||||
prev_len = self.len();
|
||||
|
||||
for undo_entry in undo_log {
|
||||
match undo_entry {
|
||||
&AddConstraint(Constraint::VarSubVar(a, b)) => {
|
||||
self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddConstraint(Constraint::RegSubVar(a, b)) => {
|
||||
self.add_edge(a, tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddConstraint(Constraint::VarSubReg(a, b)) => {
|
||||
self.add_edge(tcx.mk_region(ReVar(a)), b);
|
||||
}
|
||||
&AddConstraint(Constraint::RegSubReg(a, b)) => {
|
||||
self.add_edge(a, b);
|
||||
}
|
||||
&AddGiven(a, b) => {
|
||||
self.add_edge(a, tcx.mk_region(ReVar(b)));
|
||||
}
|
||||
&AddVerify(i) => {
|
||||
span_bug!(
|
||||
verifys[i].origin.span(),
|
||||
"we never add verifications while doing higher-ranked things",
|
||||
)
|
||||
}
|
||||
&Purged | &AddCombination(..) | &AddVar(..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
|
||||
self.regions
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.regions.len()
|
||||
}
|
||||
|
||||
fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
|
||||
if self.directions.incoming {
|
||||
if self.regions.contains(&target) {
|
||||
self.regions.insert(source);
|
||||
}
|
||||
}
|
||||
|
||||
if self.directions.outgoing {
|
||||
if self.regions.contains(&source) {
|
||||
self.regions.insert(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -771,13 +771,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
&ty::Predicate::RegionOutlives(ref binder) => {
|
||||
if select
|
||||
.infcx()
|
||||
.region_outlives_predicate(&dummy_cause, binder)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
let () = select.infcx().region_outlives_predicate(&dummy_cause, binder);
|
||||
}
|
||||
&ty::Predicate::TypeOutlives(ref binder) => {
|
||||
match (
|
||||
|
@ -728,12 +728,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref predicate) => {
|
||||
let predicate = self.resolve_type_vars_if_possible(predicate);
|
||||
let err = self.region_outlives_predicate(&obligation.cause,
|
||||
&predicate).err().unwrap();
|
||||
struct_span_err!(self.tcx.sess, span, E0279,
|
||||
"the requirement `{}` is not satisfied (`{}`)",
|
||||
predicate, err)
|
||||
// These errors should show up as region
|
||||
// inference failures.
|
||||
panic!("region outlives {:?} failed", predicate);
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
|
||||
|
@ -331,10 +331,8 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref binder) => {
|
||||
match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
|
||||
Ok(()) => ProcessResult::Changed(vec![]),
|
||||
Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
|
||||
}
|
||||
let () = self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder);
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(ref binder) => {
|
||||
|
@ -13,7 +13,7 @@ use super::{VtableImplData, VtableClosureData, VtableGeneratorData, VtableFnPoin
|
||||
use super::util;
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use infer::{InferCtxt, InferOk};
|
||||
use infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
use mir::interpret::ConstValue;
|
||||
use mir::interpret::{GlobalId};
|
||||
@ -192,28 +192,12 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>(
|
||||
obligation);
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
infcx.commit_if_ok(|snapshot| {
|
||||
let (placeholder_predicate, placeholder_map) =
|
||||
infcx.commit_if_ok(|_| {
|
||||
let (placeholder_predicate, _) =
|
||||
infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
|
||||
let skol_obligation = obligation.with(placeholder_predicate);
|
||||
let r = match project_and_unify_type(selcx, &skol_obligation) {
|
||||
Ok(result) => {
|
||||
let span = obligation.cause.span;
|
||||
match infcx.leak_check(false, span, &placeholder_map, snapshot) {
|
||||
Ok(()) => Ok(infcx.plug_leaks(placeholder_map, snapshot, result)),
|
||||
Err(e) => {
|
||||
debug!("poly_project_and_unify_type: leak check encountered error {:?}", e);
|
||||
Err(MismatchedProjectionTypes { err: e })
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
Err(e)
|
||||
}
|
||||
};
|
||||
|
||||
r
|
||||
let placeholder_obligation = obligation.with(placeholder_predicate);
|
||||
project_and_unify_type(selcx, &placeholder_obligation)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1443,17 +1427,25 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
|
||||
fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
poly_projection: ty::PolyProjectionPredicate<'tcx>)
|
||||
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>)
|
||||
-> Progress<'tcx>
|
||||
{
|
||||
let infcx = selcx.infcx();
|
||||
let cause = obligation.cause.clone();
|
||||
let cause = &obligation.cause;
|
||||
let param_env = obligation.param_env;
|
||||
let trait_ref = obligation.predicate.trait_ref(infcx.tcx);
|
||||
match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) {
|
||||
Ok(InferOk { value: ty_match, obligations }) => {
|
||||
|
||||
let (cache_entry, _) =
|
||||
infcx.replace_bound_vars_with_fresh_vars(
|
||||
cause.span,
|
||||
LateBoundRegionConversionTime::HigherRankedType,
|
||||
&poly_cache_entry);
|
||||
|
||||
let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
|
||||
let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
|
||||
match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
|
||||
Ok(InferOk { value: _, obligations }) => {
|
||||
Progress {
|
||||
ty: ty_match.value,
|
||||
ty: cache_entry.ty,
|
||||
obligations,
|
||||
}
|
||||
}
|
||||
@ -1463,7 +1455,7 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
|
||||
"Failed to unify obligation `{:?}` \
|
||||
with poly_projection `{:?}`: {:?}",
|
||||
obligation,
|
||||
poly_projection,
|
||||
poly_cache_entry,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ use super::{
|
||||
|
||||
use dep_graph::{DepKind, DepNodeIndex};
|
||||
use hir::def_id::DefId;
|
||||
use infer::{self, InferCtxt, InferOk, TypeFreshener};
|
||||
use infer::{InferCtxt, InferOk, TypeFreshener};
|
||||
use middle::lang_items;
|
||||
use mir::interpret::GlobalId;
|
||||
use ty::fast_reject;
|
||||
@ -44,7 +44,6 @@ use rustc_target::spec::abi::Abi;
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
||||
@ -1633,8 +1632,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
_ => return,
|
||||
}
|
||||
|
||||
let result = self.infcx.probe(|snapshot| {
|
||||
self.match_projection_obligation_against_definition_bounds(obligation, snapshot)
|
||||
let result = self.infcx.probe(|_| {
|
||||
self.match_projection_obligation_against_definition_bounds(obligation)
|
||||
});
|
||||
|
||||
if result {
|
||||
@ -1645,16 +1644,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
fn match_projection_obligation_against_definition_bounds(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> bool {
|
||||
let poly_trait_predicate = self.infcx()
|
||||
.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
let (skol_trait_predicate, placeholder_map) = self.infcx()
|
||||
let (skol_trait_predicate, _) = self.infcx()
|
||||
.replace_bound_vars_with_placeholders(&poly_trait_predicate);
|
||||
debug!(
|
||||
"match_projection_obligation_against_definition_bounds: \
|
||||
skol_trait_predicate={:?} placeholder_map={:?}",
|
||||
skol_trait_predicate, placeholder_map
|
||||
skol_trait_predicate={:?}",
|
||||
skol_trait_predicate,
|
||||
);
|
||||
|
||||
let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty {
|
||||
@ -1691,8 +1689,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation,
|
||||
bound.clone(),
|
||||
skol_trait_predicate.trait_ref.clone(),
|
||||
&placeholder_map,
|
||||
snapshot,
|
||||
)
|
||||
})
|
||||
});
|
||||
@ -1710,12 +1706,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation,
|
||||
bound,
|
||||
skol_trait_predicate.trait_ref.clone(),
|
||||
&placeholder_map,
|
||||
snapshot,
|
||||
);
|
||||
|
||||
self.infcx.pop_placeholders(placeholder_map, snapshot);
|
||||
|
||||
assert!(result);
|
||||
true
|
||||
}
|
||||
@ -1727,20 +1719,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
trait_bound: ty::PolyTraitRef<'tcx>,
|
||||
skol_trait_ref: ty::TraitRef<'tcx>,
|
||||
placeholder_map: &infer::PlaceholderMap<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> bool {
|
||||
debug_assert!(!skol_trait_ref.has_escaping_bound_vars());
|
||||
if self.infcx
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.sup(ty::Binder::dummy(skol_trait_ref), trait_bound)
|
||||
.is_err()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
self.infcx
|
||||
.leak_check(false, obligation.cause.span, placeholder_map, snapshot)
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
@ -1942,14 +1925,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation.predicate.def_id(),
|
||||
obligation.predicate.skip_binder().trait_ref.self_ty(),
|
||||
|impl_def_id| {
|
||||
self.infcx.probe(|snapshot| {
|
||||
if let Ok(placeholder_map) = self.match_impl(impl_def_id, obligation, snapshot)
|
||||
self.infcx.probe(|_| {
|
||||
if let Ok(_substs) = self.match_impl(impl_def_id, obligation)
|
||||
{
|
||||
candidates.vec.push(ImplCandidate(impl_def_id));
|
||||
|
||||
// N.B., we can safely drop the placeholder map
|
||||
// since we are in a probe.
|
||||
mem::drop(placeholder_map);
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -2607,8 +2586,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
// binder moved -\
|
||||
let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
|
||||
|
||||
self.infcx.in_snapshot(|snapshot| {
|
||||
let (skol_ty, placeholder_map) = self.infcx
|
||||
self.infcx.in_snapshot(|_| {
|
||||
let (skol_ty, _) = self.infcx
|
||||
.replace_bound_vars_with_placeholders(&ty);
|
||||
let Normalized {
|
||||
value: normalized_ty,
|
||||
@ -2629,8 +2608,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
&[],
|
||||
);
|
||||
obligations.push(skol_obligation);
|
||||
self.infcx
|
||||
.plug_leaks(placeholder_map, snapshot, obligations)
|
||||
obligations
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@ -2721,9 +2699,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
|
||||
self.infcx.in_snapshot(|snapshot| {
|
||||
self.infcx.in_snapshot(|_| {
|
||||
let result =
|
||||
self.match_projection_obligation_against_definition_bounds(obligation, snapshot);
|
||||
self.match_projection_obligation_against_definition_bounds(obligation);
|
||||
assert!(result);
|
||||
})
|
||||
}
|
||||
@ -2840,9 +2818,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
nested,
|
||||
);
|
||||
|
||||
let trait_obligations: Vec<PredicateObligation<'_>> = self.infcx.in_snapshot(|snapshot| {
|
||||
let trait_obligations: Vec<PredicateObligation<'_>> = self.infcx.in_snapshot(|_| {
|
||||
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
|
||||
let (trait_ref, placeholder_map) = self.infcx
|
||||
let (trait_ref, _) = self.infcx
|
||||
.replace_bound_vars_with_placeholders(&poly_trait_ref);
|
||||
let cause = obligation.derived_cause(ImplDerivedObligation);
|
||||
self.impl_or_trait_obligations(
|
||||
@ -2851,8 +2829,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation.param_env,
|
||||
trait_def_id,
|
||||
&trait_ref.substs,
|
||||
placeholder_map,
|
||||
snapshot,
|
||||
)
|
||||
});
|
||||
|
||||
@ -2877,8 +2853,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
|
||||
// First, create the substitutions by matching the impl again,
|
||||
// this time not in a probe.
|
||||
self.infcx.in_snapshot(|snapshot| {
|
||||
let (substs, placeholder_map) = self.rematch_impl(impl_def_id, obligation, snapshot);
|
||||
self.infcx.in_snapshot(|_| {
|
||||
let substs = self.rematch_impl(impl_def_id, obligation);
|
||||
debug!("confirm_impl_candidate: substs={:?}", substs);
|
||||
let cause = obligation.derived_cause(ImplDerivedObligation);
|
||||
self.vtable_impl(
|
||||
@ -2887,8 +2863,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
cause,
|
||||
obligation.recursion_depth + 1,
|
||||
obligation.param_env,
|
||||
placeholder_map,
|
||||
snapshot,
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -2900,12 +2874,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: usize,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
placeholder_map: infer::PlaceholderMap<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> VtableImplData<'tcx, PredicateObligation<'tcx>> {
|
||||
debug!(
|
||||
"vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, placeholder_map={:?})",
|
||||
impl_def_id, substs, recursion_depth, placeholder_map
|
||||
"vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})",
|
||||
impl_def_id, substs, recursion_depth,
|
||||
);
|
||||
|
||||
let mut impl_obligations = self.impl_or_trait_obligations(
|
||||
@ -2914,8 +2886,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
param_env,
|
||||
impl_def_id,
|
||||
&substs.value,
|
||||
placeholder_map,
|
||||
snapshot,
|
||||
);
|
||||
|
||||
debug!(
|
||||
@ -3044,8 +3014,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation, alias_def_id
|
||||
);
|
||||
|
||||
self.infcx.in_snapshot(|snapshot| {
|
||||
let (predicate, placeholder_map) = self.infcx
|
||||
self.infcx.in_snapshot(|_| {
|
||||
let (predicate, _) = self.infcx()
|
||||
.replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
let trait_ref = predicate.trait_ref;
|
||||
let trait_def_id = trait_ref.def_id;
|
||||
@ -3057,8 +3027,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
obligation.param_env,
|
||||
trait_def_id,
|
||||
&substs,
|
||||
placeholder_map,
|
||||
snapshot,
|
||||
);
|
||||
|
||||
debug!(
|
||||
@ -3473,13 +3441,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
&mut self,
|
||||
impl_def_id: DefId,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> (
|
||||
Normalized<'tcx, &'tcx Substs<'tcx>>,
|
||||
infer::PlaceholderMap<'tcx>,
|
||||
) {
|
||||
match self.match_impl(impl_def_id, obligation, snapshot) {
|
||||
Ok((substs, placeholder_map)) => (substs, placeholder_map),
|
||||
) -> Normalized<'tcx, &'tcx Substs<'tcx>> {
|
||||
match self.match_impl(impl_def_id, obligation) {
|
||||
Ok(substs) => substs,
|
||||
Err(()) => {
|
||||
bug!(
|
||||
"Impl {:?} was matchable against {:?} but now is not",
|
||||
@ -3494,14 +3458,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
&mut self,
|
||||
impl_def_id: DefId,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> Result<
|
||||
(
|
||||
Normalized<'tcx, &'tcx Substs<'tcx>>,
|
||||
infer::PlaceholderMap<'tcx>,
|
||||
),
|
||||
(),
|
||||
> {
|
||||
) -> Result<Normalized<'tcx, &'tcx Substs<'tcx>>, ()> {
|
||||
let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
|
||||
|
||||
// Before we create the substitutions and everything, first
|
||||
@ -3511,7 +3468,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let (skol_obligation, placeholder_map) = self.infcx()
|
||||
let (skol_obligation, _) = self.infcx()
|
||||
.replace_bound_vars_with_placeholders(&obligation.predicate);
|
||||
let skol_obligation_trait_ref = skol_obligation.trait_ref;
|
||||
|
||||
@ -3543,22 +3500,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
.map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
|
||||
nested_obligations.extend(obligations);
|
||||
|
||||
if let Err(e) =
|
||||
self.infcx
|
||||
.leak_check(false, obligation.cause.span, &placeholder_map, snapshot)
|
||||
{
|
||||
debug!("match_impl: failed leak check due to `{}`", e);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
debug!("match_impl: success impl_substs={:?}", impl_substs);
|
||||
Ok((
|
||||
Normalized {
|
||||
value: impl_substs,
|
||||
obligations: nested_obligations,
|
||||
},
|
||||
placeholder_map,
|
||||
))
|
||||
Ok(Normalized {
|
||||
value: impl_substs,
|
||||
obligations: nested_obligations,
|
||||
})
|
||||
}
|
||||
|
||||
fn fast_reject_trait_refs(
|
||||
@ -3714,8 +3660,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
def_id: DefId, // of impl or trait
|
||||
substs: &Substs<'tcx>, // for impl or trait
|
||||
placeholder_map: infer::PlaceholderMap<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
debug!("impl_or_trait_obligations(def_id={:?})", def_id);
|
||||
let tcx = self.tcx();
|
||||
@ -3777,8 +3721,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
let mut seen = FxHashSet::default();
|
||||
predicates.retain(|i| seen.insert(i.clone()));
|
||||
}
|
||||
self.infcx()
|
||||
.plug_leaks(placeholder_map, snapshot, predicates)
|
||||
|
||||
predicates
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user