use rustc::infer::canonical::{Canonical, CanonicalVarInfos};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc::traits::query::Fallible;
-use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use rustc::ty::fold::{TypeFoldable, TypeVisitor};
use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc::ty::subst::Kind;
use rustc::ty::{self, CanonicalTy, CanonicalVar, RegionVid, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::IndexVec;
-use std::mem;
pub(super) fn sub_types<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
/// When we encounter a canonical variable `var` in the output,
/// equate it with `kind`. If the variable has been previously
/// equated, then equate it again.
- fn equate_var(
+ fn relate_var(
&mut self,
- universal_regions: &UniversalRegions<'tcx>,
var: CanonicalVar,
b_kind: Kind<'tcx>,
) -> RelateResult<'tcx, Kind<'tcx>> {
debug!("equate_var(var={:?}, b_kind={:?})", var, b_kind);
- // We only encounter canonical variables when equating.
- assert_eq!(self.ambient_variance, ty::Variance::Invariant);
-
- // The canonical variable already had a value. Equate that
- // value with `b`.
- if let Some(a_kind) = self.canonical_var_values[var] {
- debug!("equate_var: a_kind={:?}", a_kind);
+ let generalized_kind = match self.canonical_var_values[var] {
+ Some(v) => v,
+ None => {
+ let generalized_kind = self.generalize_value(b_kind);
+ self.canonical_var_values[var] = Some(generalized_kind);
+ generalized_kind
+ }
+ };
- // The values we extract from `canonical_var_values` have
- // been "instantiated" and hence the set of scopes we have
- // doesn't matter -- just to be sure, put an empty vector
- // in there.
- let old_a_scopes = mem::replace(&mut self.a_scopes, vec![]);
- let result = self.relate(&a_kind, &b_kind);
- self.a_scopes = old_a_scopes;
+ // The generalized values we extract from `canonical_var_values` have
+ // been fully instantiated and hence the set of scopes we have
+ // doesn't matter -- just to be sure, put an empty vector
+ // in there.
+ let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
- debug!("equate_var: complete, result = {:?}", result);
- return result;
- }
+ // Relate the generalized kind to the original one.
+ let result = self.relate(&generalized_kind, &b_kind);
- // Not yet. Capture the value from the RHS and carry on.
- let closed_kind =
- self.instantiate_traversed_binders(universal_regions, &self.b_scopes, b_kind);
- self.canonical_var_values[var] = Some(closed_kind);
- debug!(
- "equate_var: capturing value {:?}",
- self.canonical_var_values[var]
- );
+ // Restore the old scopes now.
+ self.a_scopes = old_a_scopes;
- // FIXME -- technically, we should add some sort of
- // assertion that this value can be named in the universe
- // of the canonical variable. But in practice these
- // canonical variables only arise presently in cases where
- // they are in the root universe and the main typeck has
- // ensured there are no universe errors. So we just kind
- // of over look this right now.
- Ok(b_kind)
+ debug!("equate_var: complete, result = {:?}", result);
+ return result;
}
- /// As we traverse types and pass through binders, we push the
- /// values for each of the regions bound by those binders onto
- /// `scopes`. This function goes through `kind` and replaces any
- /// references into those scopes with the corresponding free
- /// region. Thus the resulting value should have no escaping
- /// references to bound things and can be transported into other
- /// scopes.
- fn instantiate_traversed_binders(
+ fn generalize_value(
&self,
- universal_regions: &UniversalRegions<'tcx>,
- scopes: &[BoundRegionScope],
kind: Kind<'tcx>,
) -> Kind<'tcx> {
- let k = kind.fold_with(&mut BoundReplacer {
+ TypeGeneralizer {
type_rel: self,
first_free_index: ty::INNERMOST,
- universal_regions,
- scopes: scopes,
- });
+ ambient_variance: self.ambient_variance,
- assert!(!k.has_escaping_regions());
-
- k
+ // These always correspond to an `_` or `'_` written by
+ // user, and those are always in the root universe.
+ universe: ty::UniverseIndex::ROOT,
+ }.relate(&kind, &kind)
+ .unwrap()
}
}
// Watch out for the case that we are matching a `?T` against the
// right-hand side.
if let ty::Infer(ty::CanonicalTy(var)) = a.sty {
- if let Some(&mut BorrowCheckContext {
- universal_regions, ..
- }) = self.borrowck_context
- {
- self.equate_var(universal_regions, var, b.into())?;
- Ok(a)
- } else {
- // if NLL is not enabled just ignore these variables
- // for now; in that case we're just doing a "sanity
- // check" anyway, and this only affects user-given
- // annotations like `let x: Vec<_> = ...` -- and then
- // only if the user uses type aliases to make a type
- // variable repeat more than once.
- Ok(a)
- }
+ self.relate_var(var, b.into())?;
+ Ok(a)
} else {
debug!(
"tys(a={:?}, b={:?}, variance={:?})",
}) = self.borrowck_context
{
if let ty::ReCanonical(var) = a {
- self.equate_var(universal_regions, *var, b.into())?;
+ self.relate_var(*var, b.into())?;
return Ok(a);
}
}
}
-/// When we encounter a binder like `for<..> fn(..)`, we actually have
-/// to walk the `fn` value to find all the values bound by the `for`
-/// (these are not explicitly present in the ty representation right
-/// now). This visitor handles that: it descends the type, tracking
-/// binder depth, and finds late-bound regions targeting the
-/// `for<..`>. For each of those, it creates an entry in
-/// `bound_region_scope`.
-struct BoundReplacer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
+/// The "type generalize" is used when handling inference variables.
+///
+/// The basic strategy for handling a constraint like `?A <: B` is to
+/// apply a "generalization strategy" to the type `B` -- this replaces
+/// all the lifetimes in the type `B` with fresh inference
+/// variables. (You can read more about the strategy in this [blog
+/// post].)
+///
+/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
+/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
+/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
+/// establishes `'0: 'x` as a constraint.
+///
+/// As a side-effect of this generalization procedure, we also replace
+/// all the bound regions that we have traversed with concrete values,
+/// so that the resulting generalized type is independent from the
+/// scopes.
+///
+/// [blog post]: http://smallcultfollowing.com/babysteps/blog/2014/07/09/an-experimental-new-type-inference-scheme-for-rust/
+struct TypeGeneralizer<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
type_rel: &'me TypeRelating<'me, 'bccx, 'gcx, 'tcx>,
+
+ /// After we generalize this type, we are going to relative it to
+ /// some other type. What will be the variance at this point?
+ ambient_variance: ty::Variance,
+
first_free_index: ty::DebruijnIndex,
- universal_regions: &'me UniversalRegions<'tcx>,
- scopes: &'me [BoundRegionScope],
+
+ universe: ty::UniverseIndex,
}
-impl TypeFolder<'gcx, 'tcx> for BoundReplacer<'me, 'bccx, 'gcx, 'tcx> {
- fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
- self.type_rel.tcx()
+impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'bbcx, 'gcx, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
+ self.type_rel.infcx.tcx
}
- fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> {
- self.first_free_index.shift_in(1);
- let result = t.super_fold_with(self);
- self.first_free_index.shift_out(1);
- result
+ fn tag(&self) -> &'static str {
+ "nll::generalizer"
+ }
+
+ fn a_is_expected(&self) -> bool {
+ true
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- let tcx = self.tcx();
+ fn relate_with_variance<T: Relate<'tcx>>(
+ &mut self,
+ variance: ty::Variance,
+ a: &T,
+ b: &T,
+ ) -> RelateResult<'tcx, T> {
+ debug!(
+ "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
+ variance, a, b
+ );
+
+ let old_ambient_variance = self.ambient_variance;
+ self.ambient_variance = self.ambient_variance.xform(variance);
- if let ty::ReLateBound(debruijn, _) = r {
+ debug!(
+ "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
+ self.ambient_variance
+ );
+
+ let r = self.relate(a, b)?;
+
+ self.ambient_variance = old_ambient_variance;
+
+ debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
+
+ Ok(r)
+ }
+
+ fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ debug!("TypeGeneralizer::tys(a={:?})", a,);
+
+ match a.sty {
+ ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
+ bug!(
+ "unexpected inference variable encountered in NLL generalization: {:?}",
+ a
+ );
+ }
+
+ _ => relate::super_relate_tys(self, a, a),
+ }
+ }
+
+ fn regions(
+ &mut self,
+ a: ty::Region<'tcx>,
+ _: ty::Region<'tcx>,
+ ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+ debug!("TypeGeneralizer::regions(a={:?})", a,);
+
+ if let ty::ReLateBound(debruijn, _) = a {
if *debruijn < self.first_free_index {
- return r;
+ return Ok(a);
}
}
- let region_vid = self.type_rel.replace_bound_region(
- self.universal_regions,
- r,
- self.first_free_index,
- self.scopes,
- );
+ // For now, we just always create a fresh region variable to
+ // replace all the regions in the source type. In the main
+ // type checker, we special case the case where the ambient
+ // variance is `Invariant` and try to avoid creating a fresh
+ // region variable, but since this comes up so much less in
+ // NLL (only when users use `_` etc) it is much less
+ // important.
+ //
+ // As an aside, since these new variables are created in
+ // `self.universe` universe, this also serves to enforce the
+ // universe scoping rules.
+ //
+ // FIXME -- if the ambient variance is bivariant, though, we
+ // may however need to check well-formedness or risk a problem
+ // like #41677 again.
+
+ let replacement_region_vid = self.type_rel
+ .infcx
+ .next_nll_region_var_in_universe(NLLRegionVariableOrigin::Existential, self.universe);
+
+ Ok(replacement_region_vid)
+ }
- tcx.mk_region(ty::ReVar(region_vid))
+ fn binders<T>(
+ &mut self,
+ a: &ty::Binder<T>,
+ _: &ty::Binder<T>,
+ ) -> RelateResult<'tcx, ty::Binder<T>>
+ where
+ T: Relate<'tcx>,
+ {
+ debug!("TypeGeneralizer::binders(a={:?})", a,);
+
+ self.first_free_index.shift_in(1);
+ let result = self.relate(a.skip_binder(), a.skip_binder())?;
+ self.first_free_index.shift_out(1);
+ Ok(ty::Binder::bind(result))
}
}