]> git.lizzy.rs Git - rust.git/commitdiff
Implement TypeRelation::consts
authorvarkor <github@varkor.com>
Fri, 8 Mar 2019 01:19:13 +0000 (01:19 +0000)
committervarkor <github@varkor.com>
Wed, 1 May 2019 22:10:57 +0000 (23:10 +0100)
Co-Authored-By: Gabriel Smith <yodaldevoid@users.noreply.github.com>
src/librustc/infer/canonical/canonicalizer.rs
src/librustc/infer/combine.rs
src/librustc/infer/equate.rs
src/librustc/infer/glb.rs
src/librustc/infer/lub.rs
src/librustc/infer/nll_relate/mod.rs
src/librustc/infer/sub.rs
src/librustc/ty/_match.rs
src/librustc_traits/chalk_context/resolvent_ops.rs

index 9bd7f4c02d7beeeff068bfae71f37cd6fe6a9903..0fc13bdaee65ff137af229a3a2ea5c58db9a2a86 100644 (file)
     OriginalQueryValues,
 };
 use crate::infer::InferCtxt;
+use crate::mir::interpret::ConstValue;
 use std::sync::atomic::Ordering;
 use crate::ty::fold::{TypeFoldable, TypeFolder};
 use crate::ty::subst::Kind;
-use crate::ty::{self, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags};
+use crate::ty::{self, BoundVar, InferConst, Lift, List, Ty, TyCtxt, TypeFlags};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
@@ -432,6 +433,54 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             }
         }
     }
+
+    fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
+        if let ty::LazyConst::Evaluated(ct) = c {
+            match ct.val {
+                ConstValue::Infer(InferConst::Var(vid)) => {
+                    debug!("canonical: const var found with vid {:?}", vid);
+                    match self.infcx.unwrap().probe_const_var(vid) {
+                        Ok(c) => {
+                            debug!("(resolved to {:?})", c);
+                            return self.fold_const(c);
+                        }
+
+                        // `ConstVar(vid)` is unresolved, track its universe index in the
+                        // canonicalized result
+                        Err(mut ui) => {
+                            if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk {
+                                // FIXME: perf problem described in #55921.
+                                ui = ty::UniverseIndex::ROOT;
+                            }
+                            return self.canonicalize_const_var(
+                                CanonicalVarInfo {
+                                    kind: CanonicalVarKind::Const(ui)
+                                },
+                                c
+                            );
+                        }
+                    }
+                }
+                ConstValue::Infer(InferConst::Fresh(_)) => {
+                    bug!("encountered a fresh const during canonicalization")
+                }
+                ConstValue::Infer(InferConst::Canonical(debruijn, _)) => {
+                    if debruijn >= self.binder_index {
+                        bug!("escaping bound type during canonicalization")
+                    } else {
+                        return c;
+                    }
+                }
+                _ => {}
+            }
+        }
+
+        if c.type_flags().intersects(self.needs_canonical_flags) {
+            c.super_fold_with(self)
+        } else {
+            c
+        }
+    }
 }
 
 impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
@@ -625,7 +674,7 @@ fn canonical_var_for_region(
     /// `ty_var`.
     fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo, ty_var: Ty<'tcx>) -> Ty<'tcx> {
         let infcx = self.infcx.expect("encountered ty-var without infcx");
-        let bound_to = infcx.shallow_resolve(ty_var);
+        let bound_to = infcx.shallow_resolve_type(ty_var);
         if bound_to != ty_var {
             self.fold_ty(bound_to)
         } else {
index f212f6298be53542d16a9798132e198d9cd69c36..203fd25c84280ae1b60e4ba2542fe0d7ad7391f3 100644 (file)
@@ -464,7 +464,7 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
 
         debug!("generalize: t={:?}", t);
 
-        // Check to see whether the type we are genealizing references
+        // Check to see whether the type we are generalizing references
         // any other type variable related to `vid` via
         // subtyping. This is basically our "occurs check", preventing
         // us from creating infinitely sized types.
@@ -576,6 +576,32 @@ fn regions(&mut self, r: ty::Region<'tcx>, r2: ty::Region<'tcx>)
         // very descriptive origin for this region variable.
         Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
     }
+
+    fn consts(
+        &mut self,
+        c: &'tcx ty::LazyConst<'tcx>,
+        c2: &'tcx ty::LazyConst<'tcx>
+    ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
+        assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
+
+        match c {
+            LazyConst::Evaluated(ty::Const {
+                val: ConstValue::Infer(InferConst::Var(vid)),
+                ..
+            }) => {
+                let mut variable_table = self.infcx.const_unification_table.borrow_mut();
+                match variable_table.probe(*vid).known() {
+                    Some(u) => {
+                        self.relate(&u, &u)
+                    }
+                    None => Ok(c),
+                }
+            }
+            _ => {
+                relate::super_relate_consts(self, c, c)
+            }
+        }
+    }
 }
 
 pub trait RelateResultCompare<'tcx, T> {
index 31b01eecf5cb6e88231f428b7f908c0a93f41178..e94996a0b99a3cd0976527f0d00d7eefc1efc588 100644 (file)
@@ -1,12 +1,13 @@
-use super::combine::{CombineFields, RelationDir};
-use super::{Subtype};
+use super::combine::{CombineFields, RelationDir, const_unification_error};
+use super::Subtype;
 
 use crate::hir::def_id::DefId;
 
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{self, Ty, TyCtxt, InferConst};
 use crate::ty::TyVar;
 use crate::ty::subst::SubstsRef;
 use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use crate::mir::interpret::ConstValue;
 
 /// Ensures `a` is made equal to `b`. Returns `a` on success.
 pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
@@ -100,6 +101,47 @@ fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
         Ok(a)
     }
 
+    fn consts(
+        &mut self,
+        a: &'tcx ty::LazyConst<'tcx>,
+        b: &'tcx ty::LazyConst<'tcx>,
+    ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
+        debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
+        if a == b { return Ok(a); }
+
+        let infcx = self.fields.infcx;
+        let a = infcx.const_unification_table.borrow_mut().replace_if_possible(a);
+        let b = infcx.const_unification_table.borrow_mut().replace_if_possible(b);
+        let a_is_expected = self.a_is_expected();
+        if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) {
+            match (a_eval.val, b_eval.val) {
+                (ConstValue::Infer(InferConst::Var(a_vid)),
+                 ConstValue::Infer(InferConst::Var(b_vid))) => {
+                    infcx.const_unification_table
+                        .borrow_mut()
+                        .unify_var_var(a_vid, b_vid)
+                        .map_err(|e| const_unification_error(a_is_expected, e))?;
+                    return Ok(a);
+                }
+
+                (ConstValue::Infer(InferConst::Var(a_id)), _) => {
+                    self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?;
+                    return Ok(a);
+                }
+
+                (_, ConstValue::Infer(InferConst::Var(b_id))) => {
+                    self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?;
+                    return Ok(a);
+                }
+
+                _ => {}
+            }
+        }
+
+        self.fields.infcx.super_combine_consts(self, a, b)?;
+        Ok(a)
+    }
+
     fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
index 910c6571853dc078580721c9068b19672b41b876..dde43d2072271ead492654ea2a31d062dc70d0ff 100644 (file)
@@ -60,6 +60,19 @@ fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
         Ok(self.fields.infcx.borrow_region_constraints().glb_regions(self.tcx(), origin, a, b))
     }
 
+    fn consts(
+        &mut self,
+        a: &'tcx ty::LazyConst<'tcx>,
+        b: &'tcx ty::LazyConst<'tcx>,
+    ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
+        debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
+        if a == b {
+            return Ok(a);
+        }
+
+        self.fields.infcx.super_combine_consts(self, a, b)
+    }
+
     fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
index f9eb60d82d17b5c38d6aa61e5514dc4f8c0b65a7..2a06886d94b68c3161ea29030bdce0dff677c35a 100644 (file)
@@ -60,6 +60,19 @@ fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
         Ok(self.fields.infcx.borrow_region_constraints().lub_regions(self.tcx(), origin, a, b))
     }
 
+    fn consts(
+        &mut self,
+        a: &'tcx ty::LazyConst<'tcx>,
+        b: &'tcx ty::LazyConst<'tcx>,
+    ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
+        debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
+        if a == b {
+            return Ok(a);
+        }
+
+        self.fields.infcx.super_combine_consts(self, a, b)
+    }
+
     fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
index 753fd04aac38a0eae7030947652592da87e29428..91a1e0a13bc2f125b1a2be926a5233cc3b30c14e 100644 (file)
@@ -27,7 +27,7 @@
 use crate::ty::fold::{TypeFoldable, TypeVisitor};
 use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use crate::ty::subst::Kind;
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{self, Ty, TyCtxt, InferConst};
 use rustc_data_structures::fx::FxHashMap;
 use std::fmt::Debug;
 
@@ -537,10 +537,10 @@ fn relate_with_variance<T: Relate<'tcx>>(
     }
 
     fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        let a = self.infcx.shallow_resolve(a);
+        let a = self.infcx.shallow_resolve_type(a);
 
         if !D::forbid_inference_vars() {
-            b = self.infcx.shallow_resolve(b);
+            b = self.infcx.shallow_resolve_type(b);
         }
 
         match (&a.sty, &b.sty) {
@@ -608,6 +608,24 @@ fn regions(
         Ok(a)
     }
 
+    fn consts(
+        &mut self,
+        a: &'tcx ty::LazyConst<'tcx>,
+        b: &'tcx ty::LazyConst<'tcx>,
+    ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
+        if let ty::LazyConst::Evaluated(ty::Const {
+            val: ConstValue::Infer(InferConst::Canonical(_, _)),
+            ..
+        }) = a {
+            // FIXME(const_generics): I'm unsure how this branch should actually be handled,
+            // so this is probably not correct.
+            self.infcx.super_combine_consts(self, a, b)
+        } else {
+            debug!("consts(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance);
+            relate::super_relate_consts(self, a, b)
+        }
+    }
+
     fn binders<T>(
         &mut self,
         a: &ty::Binder<T>,
@@ -853,7 +871,7 @@ fn relate_with_variance<T: Relate<'tcx>>(
     fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         use crate::infer::type_variable::TypeVariableValue;
 
-        debug!("TypeGeneralizer::tys(a={:?})", a,);
+        debug!("TypeGeneralizer::tys(a={:?})", a);
 
         match a.sty {
             ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_))
@@ -934,7 +952,7 @@ fn regions(
         a: ty::Region<'tcx>,
         _: ty::Region<'tcx>,
     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        debug!("TypeGeneralizer::regions(a={:?})", a,);
+        debug!("TypeGeneralizer::regions(a={:?})", a);
 
         if let ty::ReLateBound(debruijn, _) = a {
             if *debruijn < self.first_free_index {
@@ -963,6 +981,26 @@ fn regions(
         Ok(replacement_region_vid)
     }
 
+    fn consts(
+        &mut self,
+        a: &'tcx ty::LazyConst<'tcx>,
+        _: &'tcx ty::LazyConst<'tcx>,
+    ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
+        debug!("TypeGeneralizer::consts(a={:?})", a);
+
+        if let ty::LazyConst::Evaluated(ty::Const {
+            val: ConstValue::Infer(InferConst::Canonical(_, _)),
+            ..
+        }) = a {
+            bug!(
+                "unexpected inference variable encountered in NLL generalization: {:?}",
+                a
+            );
+        } else {
+            relate::super_relate_consts(self, a, a)
+        }
+    }
+
     fn binders<T>(
         &mut self,
         a: &ty::Binder<T>,
@@ -971,7 +1009,7 @@ fn binders<T>(
     where
         T: Relate<'tcx>,
     {
-        debug!("TypeGeneralizer::binders(a={:?})", a,);
+        debug!("TypeGeneralizer::binders(a={:?})", a);
 
         self.first_free_index.shift_in(1);
         let result = self.relate(a.skip_binder(), a.skip_binder())?;
index 0cff42742c30a813e74f74abab7da0209306e7c3..b285d59729110706964e151360e6e126a67a1a3b 100644 (file)
@@ -1,11 +1,12 @@
 use super::SubregionOrigin;
-use super::combine::{CombineFields, RelationDir};
+use super::combine::{CombineFields, RelationDir, const_unification_error};
 
 use crate::traits::Obligation;
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{self, Ty, TyCtxt, InferConst};
 use crate::ty::TyVar;
 use crate::ty::fold::TypeFoldable;
 use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
+use crate::mir::interpret::ConstValue;
 use std::mem;
 
 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
@@ -133,6 +134,50 @@ fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
         Ok(a)
     }
 
+    fn consts(
+        &mut self,
+        a: &'tcx ty::LazyConst<'tcx>,
+        b: &'tcx ty::LazyConst<'tcx>,
+    ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
+        debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
+        if a == b { return Ok(a); }
+
+        let infcx = self.fields.infcx;
+        let a = infcx.const_unification_table.borrow_mut().replace_if_possible(a);
+        let b = infcx.const_unification_table.borrow_mut().replace_if_possible(b);
+
+        // Consts can only be equal or unequal to each other: there's no subtyping
+        // relation, so we're just going to perform equating here instead.
+        let a_is_expected = self.a_is_expected();
+        if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) {
+            match (a_eval.val, b_eval.val) {
+                (ConstValue::Infer(InferConst::Var(a_vid)),
+                 ConstValue::Infer(InferConst::Var(b_vid))) => {
+                    infcx.const_unification_table
+                        .borrow_mut()
+                        .unify_var_var(a_vid, b_vid)
+                        .map_err(|e| const_unification_error(a_is_expected, e))?;
+                    return Ok(a);
+                }
+
+                (ConstValue::Infer(InferConst::Var(a_id)), _) => {
+                    self.fields.infcx.unify_const_variable(a_is_expected, a_id, b)?;
+                    return Ok(a);
+                }
+
+                (_, ConstValue::Infer(InferConst::Var(b_id))) => {
+                    self.fields.infcx.unify_const_variable(!a_is_expected, b_id, a)?;
+                    return Ok(a);
+                }
+
+                _ => {}
+            }
+        }
+
+        self.fields.infcx.super_combine_consts(self, a, b)?;
+        Ok(a)
+    }
+
     fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
index 07fa441bb8076e3cce51f434ef33e1e98a2ce14a..fdc695610141009539e369452e7113a551ab8148 100644 (file)
@@ -1,6 +1,7 @@
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::error::TypeError;
+use crate::ty::{self, Ty, TyCtxt, InferConst};
+use crate::ty::error::{TypeError, ConstError};
 use crate::ty::relate::{self, Relate, TypeRelation, RelateResult};
+use crate::mir::interpret::ConstValue;
 
 /// A type "A" *matches* "B" if the fresh types in B could be
 /// substituted with values so as to make it equal to A. Matching is
@@ -78,6 +79,35 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         }
     }
 
+    fn consts(
+        &mut self,
+        a: &'tcx ty::LazyConst<'tcx>,
+        b: &'tcx ty::LazyConst<'tcx>,
+    ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
+        debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
+        if a == b {
+            return Ok(a);
+        }
+
+        if let (&ty::LazyConst::Evaluated(a_eval), &ty::LazyConst::Evaluated(b_eval)) = (a, b) {
+            match (a_eval.val, b_eval.val) {
+                (_, ConstValue::Infer(InferConst::Fresh(_))) => {
+                    return Ok(a);
+                }
+
+                (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => {
+                    return Err(TypeError::ConstError(
+                        ConstError::Mismatch(relate::expected_found(self, &a, &b))
+                    ));
+                }
+
+                _ => {}
+            }
+        }
+
+        relate::super_relate_consts(self, a, b)
+    }
+
     fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
index 4f5a4996db5375309426bdebee802de1a51efb84..7fc05308754065e8abfcb60c00e53df4a54fe2f6 100644 (file)
     Environment,
     InEnvironment,
 };
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, InferConst};
 use rustc::ty::subst::Kind;
 use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc::mir::interpret::ConstValue;
 use syntax_pos::DUMMY_SP;
 
 use super::{ChalkInferenceContext, ChalkArenas, ChalkExClause, ConstrainedSubst};
@@ -203,7 +204,7 @@ fn binders<T: Relate<'tcx>>(
     }
 
     fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        let b = self.infcx.shallow_resolve(b);
+        let b = self.infcx.shallow_resolve_type(b);
         debug!("AnswerSubstitutor::tys(a = {:?}, b = {:?})", a, b);
 
         if let &ty::Bound(debruijn, bound_ty) = &a.sty {
@@ -275,4 +276,44 @@ fn regions(
 
         Ok(a)
     }
+
+    fn consts(
+        &mut self,
+        a: &'tcx ty::LazyConst<'tcx>,
+        b: &'tcx ty::LazyConst<'tcx>,
+    ) -> RelateResult<'tcx, &'tcx ty::LazyConst<'tcx>> {
+        if let ty::LazyConst::Evaluated(ty::Const {
+            val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)),
+            ..
+        }) = a {
+            if *debruijn == self.binder_index {
+                self.unify_free_answer_var(*bound_ct, b.into())?;
+                return Ok(b);
+            }
+        }
+
+        match (a, b) {
+            (
+                ty::LazyConst::Evaluated(ty::Const {
+                    val: ConstValue::Infer(InferConst::Canonical(a_debruijn, a_bound)),
+                    ..
+                }),
+                ty::LazyConst::Evaluated(ty::Const {
+                    val: ConstValue::Infer(InferConst::Canonical(b_debruijn, b_bound)),
+                    ..
+                }),
+            ) => {
+                assert_eq!(a_debruijn, b_debruijn);
+                assert_eq!(a_bound, b_bound);
+                Ok(a)
+            }
+
+            // Everything else should just be a perfect match as well,
+            // and we forbid inference variables.
+            _ => match ty::relate::super_relate_consts(self, a, b) {
+                Ok(ct) => Ok(ct),
+                Err(err) => bug!("const mismatch in `AnswerSubstitutor`: {}", err),
+            }
+        }
+    }
 }