InferCtxt,
LateBoundRegion,
HigherRankedType,
+ SubregionOrigin,
SkolemizationMap};
use super::combine::CombineFields;
use super::region_inference::{TaintDirections};
use syntax::codemap::Span;
use util::nodemap::{FnvHashMap, FnvHashSet};
+pub struct HrMatchResult<U> {
+ pub value: U,
+
+ /// Normally, when we do a higher-ranked match operation, we
+ /// expect all higher-ranked regions to be constrained as part of
+ /// the match operation. However, in the transition period for
+ /// #32330, it can happen that we sometimes have unconstrained
+ /// regions that get instantiated with fresh variables. In that
+ /// case, we collect the set of unconstrained bound regions here
+ /// and replace them with fresh variables.
+ pub unconstrained_regions: Vec<ty::BoundRegion>,
+}
+
impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
pub fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
-> RelateResult<'tcx, Binder<T>>
});
}
+ /// 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>(&self,
+ span: Span,
+ a_pair: &Binder<(T, U)>,
+ b_match: &T)
+ -> 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 skolemized region.
+ let ((a_match, a_value), skol_map) =
+ self.infcx.skolemize_late_bound_regions(a_pair, snapshot);
+
+ debug!("higher_ranked_match: a_match={:?}", a_match);
+ debug!("higher_ranked_match: skol_map={:?}", skol_map);
+
+ // Equate types now that bound regions have been replaced.
+ try!(self.equate().relate(&a_match, &b_match));
+
+ // Map each skolemized region to a vector of other regions that it
+ // must be equated with. (Note that this vector may include other
+ // skolemized regions from `skol_map`.)
+ let skol_resolution_map: FnvHashMap<_, _> =
+ skol_map
+ .iter()
+ .map(|(&br, &skol)| {
+ let tainted_regions =
+ self.infcx.tainted_regions(snapshot,
+ skol,
+ TaintDirections::incoming()); // [1]
+
+ // [1] this routine executes after the skolemized
+ // regions have been *equated* with something
+ // else, so examining the incoming edges ought to
+ // be enough to collect all constraints
+
+ (skol, (br, tainted_regions))
+ })
+ .collect();
+
+ // For each skolemized region, pick a representative -- which can
+ // be any region from the sets above, except for other members of
+ // `skol_map`. There should always be a representative if things
+ // are properly well-formed.
+ let mut unconstrained_regions = vec![];
+ let skol_representatives: FnvHashMap<_, _> =
+ skol_resolution_map
+ .iter()
+ .map(|(&skol, &(br, ref regions))| {
+ let representative =
+ regions.iter()
+ .filter(|r| !skol_resolution_map.contains_key(r))
+ .cloned()
+ .next()
+ .unwrap_or_else(|| { // [1]
+ unconstrained_regions.push(br);
+ self.infcx.next_region_var(
+ LateBoundRegion(span, br, HigherRankedType))
+ });
+
+ // [1] There should always be a representative,
+ // unless the higher-ranked region did not appear
+ // in the values being matched. We should reject
+ // as ill-formed cases that can lead to this, but
+ // right now we sometimes issue warnings (see
+ // #32330).
+
+ (skol, representative)
+ })
+ .collect();
+
+ // Equate all the members of each skolemization set with the
+ // representative.
+ for (skol, &(_br, ref regions)) in &skol_resolution_map {
+ let representative = &skol_representatives[skol];
+ debug!("higher_ranked_match: \
+ skol={:?} representative={:?} regions={:?}",
+ skol, representative, regions);
+ for region in regions.iter()
+ .filter(|&r| !skol_resolution_map.contains_key(r))
+ .filter(|&r| r != representative)
+ {
+ let origin = SubregionOrigin::Subtype(self.trace.clone());
+ self.infcx.region_vars.make_eqregion(origin,
+ *representative,
+ *region);
+ }
+ }
+
+ // Replace the skolemized regions appearing in value with
+ // their representatives
+ let a_value =
+ fold_regions_in(
+ self.tcx(),
+ &a_value,
+ |r, _| skol_representatives.get(&r).cloned().unwrap_or(r));
+
+ debug!("higher_ranked_match: value={:?}", a_value);
+
+ // We are now done with these skolemized variables.
+ self.infcx.pop_skolemized(skol_map, snapshot);
+
+ Ok(HrMatchResult {
+ value: a_value,
+ unconstrained_regions: unconstrained_regions,
+ })
+ });
+ }
+
pub fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>)
-> RelateResult<'tcx, Binder<T>>
where T: Relate<'tcx>
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
use self::combine::CombineFields;
+use self::higher_ranked::HrMatchResult;
use self::region_inference::{RegionVarBindings, RegionSnapshot};
use self::unify_key::ToType;
pub mod type_variable;
pub mod unify_key;
+#[must_use]
pub struct InferOk<'tcx, T> {
pub value: T,
pub obligations: PredicateObligations<'tcx>,
|br| self.next_region_var(LateBoundRegion(span, br, lbrct)))
}
+ /// 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,
+ origin: TypeOrigin,
+ match_a: ty::PolyProjectionPredicate<'tcx>,
+ match_b: ty::TraitRef<'tcx>)
+ -> RelateResult<HrMatchResult<Ty<'tcx>>>
+ {
+ let span = origin.span();
+ let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref;
+ let trace = TypeTrace {
+ origin: origin,
+ values: TraitRefs(ExpectedFound::new(true, match_trait_ref, match_b))
+ };
+
+ let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty));
+ self.combine_fields(true, trace)
+ .higher_ranked_match(span, &match_pair, &match_b)
+ }
+
/// See `verify_generic_bound` method in `region_inference`
pub fn verify_generic_bound(&self,
origin: SubregionOrigin<'tcx>,