]> git.lizzy.rs Git - rust.git/commitdiff
refactor so that `relate_ty_var` can accommodate vid on a or b side
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 20 Mar 2019 16:45:24 +0000 (12:45 -0400)
committerscalexm <alexandre@scalexm.fr>
Wed, 20 Mar 2019 19:17:12 +0000 (20:17 +0100)
src/librustc/infer/nll_relate/mod.rs

index 1767db3ff03731e16982bba11f0d31c83375e304..735dcffc6d16dbf2a6414fa70a9322784dec1814 100644 (file)
@@ -29,6 +29,7 @@
 use crate::ty::subst::Kind;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
+use std::fmt::Debug;
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub enum NormalizationStrategy {
@@ -294,14 +295,34 @@ fn relate_projection_ty(
         }
     }
 
-    /// Relate a type inference variable with a value type.
-    fn relate_ty_var(
+    /// Relate a type inference variable with a value type. This works
+    /// by creating a "generalization" G of the value where all the
+    /// lifetimes are replaced with fresh inference values. This
+    /// genearlization G becomes the value of the inference variable,
+    /// and is then related in turn to the value. So e.g. if you had
+    /// `vid = ?0` and `value = &'a u32`, we might first instantiate
+    /// `?0` to a type like `&'0 u32` where `'0` is a fresh variable,
+    /// and then relate `&'0 u32` with `&'a u32` (resulting in
+    /// relations between `'0` and `'a`).
+    ///
+    /// The variable `pair` can be either a `(vid, ty)` or `(ty, vid)`
+    /// -- in other words, it is always a (unresolved) inference
+    /// variable `vid` and a type `ty` that are being related, but the
+    /// vid may appear either as the "a" type or the "b" type,
+    /// depending on where it appears in the tuple. The trait
+    /// `VidValuePair` lets us work with the vid/type while preserving
+    /// the "sidedness" when necessary -- the sidedness is relevant in
+    /// particular for the variance and set of in-scope things.
+    fn relate_ty_var<PAIR: VidValuePair<'tcx>>(
         &mut self,
-        vid: ty::TyVid,
-        value_ty: Ty<'tcx>,
+        pair: PAIR,
     ) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("relate_ty_var(vid={:?}, value_ty={:?})", vid, value_ty);
+        debug!("relate_ty_var({:?})", pair);
+
+        let vid = pair.vid();
+        let value_ty = pair.value_ty();
 
+        // FIXME -- this logic assumes invariance, but that is wrong
         match value_ty.sty {
             ty::Infer(ty::TyVar(value_vid)) => {
                 // Two type variables: just equate them.
@@ -338,13 +359,13 @@ fn relate_ty_var(
         // 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![]);
+        let old_a_scopes = ::std::mem::replace(pair.vid_scopes(self), vec![]);
 
         // Relate the generalized kind to the original one.
-        let result = self.relate(&generalized_ty, &value_ty);
+        let result = pair.relate_generalized_ty(self, generalized_ty);
 
         // Restore the old scopes now.
-        self.a_scopes = old_a_scopes;
+        *pair.vid_scopes(self) = old_a_scopes;
 
         debug!("relate_ty_var: complete, result = {:?}", result);
         result
@@ -370,6 +391,104 @@ fn generalize_value<T: Relate<'tcx>>(
     }
 }
 
+/// When we instantiate a inference variable with a value in
+/// `relate_ty_var`, we always have the pair of a `TyVid` and a `Ty`,
+/// but the ordering may vary (depending on whether the inference
+/// variable was found on the `a` or `b` sides). Therefore, this trait
+/// allows us to factor out common code, while preserving the order
+/// when needed.
+trait VidValuePair<'tcx>: Debug {
+    /// Extract the inference variable (which could be either the
+    /// first or second part of the tuple).
+    fn vid(&self) -> ty::TyVid;
+
+    /// Extract the value it is being related to (which will be the
+    /// opposite part of the tuple from the vid).
+    fn value_ty(&self) -> Ty<'tcx>;
+
+    /// Extract the scopes that apply to whichever side of the tuple
+    /// the vid was found on.  See the comment where this is called
+    /// for more details on why we want them.
+    fn vid_scopes<D: TypeRelatingDelegate<'tcx>>(
+        &self,
+        relate: &'r mut TypeRelating<'_, '_, 'tcx, D>,
+    ) -> &'r mut Vec<BoundRegionScope<'tcx>>;
+
+    /// Given a generalized type G that should replace the vid, relate
+    /// G to the value, putting G on whichever side the vid would have
+    /// appeared.
+    fn relate_generalized_ty<D>(
+        &self,
+        relate: &mut TypeRelating<'_, '_, 'tcx, D>,
+        generalized_ty: Ty<'tcx>,
+    ) -> RelateResult<'tcx, Ty<'tcx>>
+    where
+        D: TypeRelatingDelegate<'tcx>;
+}
+
+impl VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) {
+    fn vid(&self) -> ty::TyVid {
+        self.0
+    }
+
+    fn value_ty(&self) -> Ty<'tcx> {
+        self.1
+    }
+
+    fn vid_scopes<D>(
+        &self,
+        relate: &'r mut TypeRelating<'_, '_, 'tcx, D>,
+    ) -> &'r mut Vec<BoundRegionScope<'tcx>>
+    where
+        D: TypeRelatingDelegate<'tcx>,
+    {
+        &mut relate.a_scopes
+    }
+
+    fn relate_generalized_ty<D>(
+        &self,
+        relate: &mut TypeRelating<'_, '_, 'tcx, D>,
+        generalized_ty: Ty<'tcx>,
+    ) -> RelateResult<'tcx, Ty<'tcx>>
+    where
+        D: TypeRelatingDelegate<'tcx>,
+    {
+        relate.relate(&generalized_ty, &self.value_ty())
+    }
+}
+
+// In this case, the "vid" is the "b" type.
+impl VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) {
+    fn vid(&self) -> ty::TyVid {
+        self.1
+    }
+
+    fn value_ty(&self) -> Ty<'tcx> {
+        self.0
+    }
+
+    fn vid_scopes<D>(
+        &self,
+        relate: &'r mut TypeRelating<'_, '_, 'tcx, D>,
+    ) -> &'r mut Vec<BoundRegionScope<'tcx>>
+    where
+        D: TypeRelatingDelegate<'tcx>,
+    {
+        &mut relate.b_scopes
+    }
+
+    fn relate_generalized_ty<D>(
+        &self,
+        relate: &mut TypeRelating<'_, '_, 'tcx, D>,
+        generalized_ty: Ty<'tcx>,
+    ) -> RelateResult<'tcx, Ty<'tcx>>
+    where
+        D: TypeRelatingDelegate<'tcx>,
+    {
+        relate.relate(&self.value_ty(), &generalized_ty)
+    }
+}
+
 impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
 where
     D: TypeRelatingDelegate<'tcx>,
@@ -427,17 +546,11 @@ fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>
                     // Forbid inference variables in the RHS.
                     bug!("unexpected inference var {:?}", b)
                 } else {
-                    // We swap the order of `a` and `b` in the call to
-                    // `relate_ty_var` below, so swap the corresponding scopes
-                    // as well.
-                    std::mem::swap(&mut self.a_scopes, &mut self.b_scopes);
-                    let res = self.relate_ty_var(vid, a);
-                    std::mem::swap(&mut self.a_scopes, &mut self.b_scopes);
-                    res
+                    self.relate_ty_var((a, vid))
                 }
             }
 
-            (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var(vid, b),
+            (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
 
             (&ty::Projection(projection_ty), _)
                 if D::normalization() == NormalizationStrategy::Lazy =>
@@ -448,12 +561,7 @@ fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>
             (_, &ty::Projection(projection_ty))
                 if D::normalization() == NormalizationStrategy::Lazy =>
             {
-                // Swap the respective scopes of `a` and `b` (see comment
-                // above).
-                std::mem::swap(&mut self.a_scopes, &mut self.b_scopes);
-                let res = self.relate_projection_ty(projection_ty, a);
-                std::mem::swap(&mut self.a_scopes, &mut self.b_scopes);
-                Ok(res)
+                Ok(self.relate_projection_ty(projection_ty, a))
             }
 
             _ => {