universe transition

Remove the leak-check and its associated machinery. Replace with
making the solver aware of universes.
This commit is contained in:
Niko Matsakis 2018-09-07 20:11:23 -04:00
parent eba2ae526b
commit b68fad670b
10 changed files with 144 additions and 799 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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