]> git.lizzy.rs Git - rust.git/commitdiff
Assume unevaluated consts are equal to the other consts and add ConstEquate obligatio...
authorBen Lewis <benlewisj@gmail.com>
Fri, 28 Feb 2020 21:03:04 +0000 (10:03 +1300)
committerBastian Kauschke <bastian_kauschke@hotmail.de>
Sun, 17 May 2020 09:01:02 +0000 (11:01 +0200)
the need to evaluate consts eagerly and therefore gets around const eval query cycles.

36 files changed:
src/librustc_infer/infer/canonical/query_response.rs
src/librustc_infer/infer/combine.rs
src/librustc_infer/infer/equate.rs
src/librustc_infer/infer/glb.rs
src/librustc_infer/infer/lub.rs
src/librustc_infer/infer/mod.rs
src/librustc_infer/infer/nll_relate/mod.rs
src/librustc_infer/infer/outlives/mod.rs
src/librustc_infer/infer/sub.rs
src/librustc_infer/traits/mod.rs
src/librustc_infer/traits/structural_impls.rs
src/librustc_infer/traits/util.rs
src/librustc_lint/builtin.rs
src/librustc_middle/ty/mod.rs
src/librustc_middle/ty/outlives.rs
src/librustc_middle/ty/print/pretty.rs
src/librustc_middle/ty/relate.rs
src/librustc_middle/ty/structural_impls.rs
src/librustc_mir/borrow_check/type_check/relate_tys.rs
src/librustc_mir/transform/qualify_min_const_fn.rs
src/librustc_trait_selection/opaque_types.rs
src/librustc_trait_selection/traits/error_reporting/mod.rs
src/librustc_trait_selection/traits/fulfill.rs
src/librustc_trait_selection/traits/object_safety.rs
src/librustc_trait_selection/traits/project.rs
src/librustc_trait_selection/traits/query/normalize.rs
src/librustc_trait_selection/traits/select.rs
src/librustc_trait_selection/traits/wf.rs
src/librustc_traits/implied_outlives_bounds.rs
src/librustc_traits/normalize_erasing_regions.rs
src/librustc_typeck/check/method/probe.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/impl_wf_check/min_specialization.rs
src/librustc_typeck/outlives/explicit.rs
src/librustdoc/clean/mod.rs

index de93baff79beb393f7afa67d5e4ecd63140bdb09..c7a7cf89b4f1b738a16a6909f15784648e48e390 100644 (file)
@@ -25,7 +25,7 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt};
+use rustc_middle::ty::{self, BoundVar, Const, Ty, TyCtxt};
 use std::fmt::Debug;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
@@ -671,6 +671,13 @@ fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
         });
     }
 
+    fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {
+        span_bug!(
+            self.cause.span(self.infcx.tcx),
+            "lazy_normalization_consts: unreachable `const_equate`"
+        );
+    }
+
     fn normalization() -> NormalizationStrategy {
         NormalizationStrategy::Eager
     }
index d4af470499670423307089a4771808979a13022e..b995ff989e97597da3507596f030d2cf5919707c 100644 (file)
@@ -164,7 +164,6 @@ pub fn super_combine_consts<R>(
             (_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
                 return self.unify_const_variable(!a_is_expected, vid, a);
             }
-
             _ => {}
         }
 
@@ -375,6 +374,20 @@ fn generalize(
         debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
         Ok(Generalization { ty, needs_wf })
     }
+
+    pub fn add_const_equate_obligation(
+        &mut self,
+        a_is_expected: bool,
+        a: &'tcx ty::Const<'tcx>,
+        b: &'tcx ty::Const<'tcx>,
+    ) {
+        let predicate = if a_is_expected {
+            ty::Predicate::ConstEquate(a, b)
+        } else {
+            ty::Predicate::ConstEquate(b, a)
+        };
+        self.obligations.push(Obligation::new(self.trace.cause.clone(), self.param_env, predicate));
+    }
 }
 
 struct Generalizer<'cx, 'tcx> {
@@ -637,6 +650,7 @@ fn consts(
                     }
                 }
             }
+            ty::ConstKind::Unevaluated(..) => Ok(c),
             _ => relate::super_relate_consts(self, c, c),
         }
     }
index d054070e292fa2ec7c09d118529c3ebe770b5d56..eebcc0ff12a6ae550a84a3de95649d79a87fb90c 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::TyVar;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, ConstKind, Ty, TyCtxt};
 
 use rustc_hir::def_id::DefId;
 
@@ -119,7 +119,17 @@ fn consts(
         a: &'tcx ty::Const<'tcx>,
         b: &'tcx ty::Const<'tcx>,
     ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
-        self.fields.infcx.super_combine_consts(self, a, b)
+        match (a.val, b.val) {
+            (ConstKind::Unevaluated(..), _) => {
+                self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+                Ok(b)
+            }
+            (_, ConstKind::Unevaluated(..)) => {
+                self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+                Ok(a)
+            }
+            _ => self.fields.infcx.super_combine_consts(self, a, b),
+        }
     }
 
     fn binders<T>(
index f95d74a9340c9fbd7920f04752795e52ca05f7a6..583e80efc7c5564d24ce609d6a90216dba212bc6 100644 (file)
@@ -79,7 +79,17 @@ fn consts(
         a: &'tcx ty::Const<'tcx>,
         b: &'tcx ty::Const<'tcx>,
     ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
-        self.fields.infcx.super_combine_consts(self, a, b)
+        match (a.val, b.val) {
+            (ty::ConstKind::Unevaluated(..), _) => {
+                self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+                Ok(b)
+            }
+            (_, ty::ConstKind::Unevaluated(..)) => {
+                self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+                Ok(a)
+            }
+            _ => self.fields.infcx.super_combine_consts(self, a, b),
+        }
     }
 
     fn binders<T>(
index 492f2b229d36d3ace1bc65d2f965d687401201b6..e613bd5dc7a891b797aa1c0ad5a4ba36912e5b8d 100644 (file)
@@ -79,7 +79,17 @@ fn consts(
         a: &'tcx ty::Const<'tcx>,
         b: &'tcx ty::Const<'tcx>,
     ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
-        self.fields.infcx.super_combine_consts(self, a, b)
+        match (a.val, b.val) {
+            (ty::ConstKind::Unevaluated(..), _) => {
+                self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+                Ok(b)
+            }
+            (_, ty::ConstKind::Unevaluated(..)) => {
+                self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+                Ok(a)
+            }
+            _ => self.fields.infcx.super_combine_consts(self, a, b),
+        }
     }
 
     fn binders<T>(
index 67632a97df792889436da53beaad639b164f553f..9c81a1153958b5a22cc5dfca7dec50cd7ac4c3ae 100644 (file)
@@ -1490,6 +1490,17 @@ pub fn report_mismatched_types(
         self.report_and_explain_type_error(trace, &err)
     }
 
+    pub fn report_mismatched_consts(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        expected: &'tcx ty::Const<'tcx>,
+        actual: &'tcx ty::Const<'tcx>,
+        err: TypeError<'tcx>,
+    ) -> DiagnosticBuilder<'tcx> {
+        let trace = TypeTrace::consts(cause, true, expected, actual);
+        self.report_and_explain_type_error(trace, &err)
+    }
+
     pub fn replace_bound_vars_with_fresh_vars<T>(
         &self,
         span: Span,
@@ -1777,6 +1788,15 @@ pub fn types(
         TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
     }
 
+    pub fn consts(
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: &'tcx ty::Const<'tcx>,
+        b: &'tcx ty::Const<'tcx>,
+    ) -> TypeTrace<'tcx> {
+        TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
+    }
+
     pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: ObligationCause::dummy(),
index 7aea26987a29f237d89b5bd093f99de5d4d8c9db..32f11abdc9797eb20951f4ac86e2c4d173951127 100644 (file)
@@ -77,6 +77,8 @@ pub trait TypeRelatingDelegate<'tcx> {
     /// delegate.
     fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
 
+    fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
+
     /// Creates a new universe index. Used when instantiating placeholders.
     fn create_next_universe(&mut self) -> ty::UniverseIndex;
 
@@ -592,8 +594,16 @@ fn consts(
             b = self.infcx.shallow_resolve(b);
         }
 
-        match b.val {
-            ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
+        match (a.val, b.val) {
+            (ty::ConstKind::Unevaluated(..), _) => {
+                self.delegate.const_equate(a, b);
+                Ok(b)
+            }
+            (_, ty::ConstKind::Unevaluated(..)) => {
+                self.delegate.const_equate(a, b);
+                Ok(a)
+            }
+            (_, ty::ConstKind::Infer(InferConst::Var(_))) if D::forbid_inference_vars() => {
                 // Forbid inference variables in the RHS.
                 bug!("unexpected inference var {:?}", b)
             }
@@ -976,6 +986,7 @@ fn consts(
                     }
                 }
             }
+            ty::ConstKind::Unevaluated(..) => Ok(a),
             _ => relate::super_relate_consts(self, a, a),
         }
     }
index ed3d86058696802f5fca9cc5017048cd351968ed..289457e2bd0c294ea1fcfa63b235d044d9caf14f 100644 (file)
@@ -19,7 +19,8 @@ pub fn explicit_outlives_bounds<'tcx>(
         | ty::Predicate::ObjectSafe(..)
         | ty::Predicate::ClosureKind(..)
         | ty::Predicate::TypeOutlives(..)
-        | ty::Predicate::ConstEvaluatable(..) => None,
+        | ty::Predicate::ConstEvaluatable(..)
+        | ty::Predicate::ConstEquate(..) => None,
         ty::Predicate::RegionOutlives(ref data) => data
             .no_bound_vars()
             .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)),
index 0abcc15d6fcd8b7f633a6f5fb5fbe0535b4bf746..91b43dd082f14f750891596a8628a37b51100a9c 100644 (file)
@@ -155,7 +155,17 @@ fn consts(
         a: &'tcx ty::Const<'tcx>,
         b: &'tcx ty::Const<'tcx>,
     ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
-        self.fields.infcx.super_combine_consts(self, a, b)
+        match (a.val, b.val) {
+            (ty::ConstKind::Unevaluated(..), _) => {
+                self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+                Ok(b)
+            }
+            (_, ty::ConstKind::Unevaluated(..)) => {
+                self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+                Ok(a)
+            }
+            _ => self.fields.infcx.super_combine_consts(self, a, b),
+        }
     }
 
     fn binders<T>(
index a8585fd293518dacbd25b8cf06cef873f91e753e..8d95904b355da7247def7b9629a384dd624b917e 100644 (file)
@@ -10,7 +10,7 @@
 
 use rustc_hir as hir;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Const, Ty};
 use rustc_span::Span;
 
 pub use self::FulfillmentErrorCode::*;
@@ -81,6 +81,7 @@ pub enum FulfillmentErrorCode<'tcx> {
     CodeSelectionError(SelectionError<'tcx>),
     CodeProjectionError(MismatchedProjectionTypes<'tcx>),
     CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
+    CodeConstEquateError(ExpectedFound<&'tcx Const<'tcx>>, TypeError<'tcx>),
     CodeAmbiguity,
 }
 
index 595a8cd768390e5d4613e2faf211baebb8e73359..c48e58c04824e03a13e3a2a461957754bb58c0d1 100644 (file)
@@ -41,6 +41,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             super::CodeSubtypeError(ref a, ref b) => {
                 write!(f, "CodeSubtypeError({:?}, {:?})", a, b)
             }
+            super::CodeConstEquateError(ref a, ref b) => {
+                write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
+            }
             super::CodeAmbiguity => write!(f, "Ambiguity"),
         }
     }
index b34685006e22301c111938ccadaed42a0ee56f57..ee903b676bae95cf7e3a600fa2ab197bd5e13635 100644 (file)
@@ -42,6 +42,8 @@ pub fn anonymize_predicate<'tcx>(
         ty::Predicate::ConstEvaluatable(def_id, substs) => {
             ty::Predicate::ConstEvaluatable(def_id, substs)
         }
+
+        ty::Predicate::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2),
     }
 }
 
@@ -187,6 +189,10 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
                 // Currently, we do not elaborate const-evaluatable
                 // predicates.
             }
+            ty::Predicate::ConstEquate(..) => {
+                // Currently, we do not elaborate const-equate
+                // predicates.
+            }
             ty::Predicate::RegionOutlives(..) => {
                 // Nothing to elaborate from `'a: 'b`.
             }
index 327dbecba26ce6f0a47206fb0d4d9099bd46cff6..bca91fb7b5d168629a4bff103892fb9eb26d2ff4 100644 (file)
@@ -1221,7 +1221,8 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'tcx>
                     ObjectSafe(..) |
                     ClosureKind(..) |
                     Subtype(..) |
-                    ConstEvaluatable(..) => continue,
+                    ConstEvaluatable(..) |
+                    ConstEquate(..) => continue,
                 };
                 if predicate.is_global() {
                     cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
index 6d6e1699feb222c37fde257fef0c083cac1f6405..36bc44f5e50329b9734a8bd37168e33b9a334b78 100644 (file)
@@ -1054,6 +1054,9 @@ pub enum Predicate<'tcx> {
 
     /// Constant initializer must evaluate successfully.
     ConstEvaluatable(DefId, SubstsRef<'tcx>),
+
+    /// Constants must be equal. The first component is the const that is expected.
+    ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
 }
 
 /// The crate outlives map is computed during typeck and contains the
@@ -1172,6 +1175,9 @@ pub fn subst_supertrait(
             Predicate::ConstEvaluatable(def_id, const_substs) => {
                 Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs))
             }
+            Predicate::ConstEquate(c1, c2) => {
+                Predicate::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs))
+            }
         }
     }
 }
@@ -1349,7 +1355,8 @@ pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> {
             | Predicate::ObjectSafe(..)
             | Predicate::ClosureKind(..)
             | Predicate::TypeOutlives(..)
-            | Predicate::ConstEvaluatable(..) => None,
+            | Predicate::ConstEvaluatable(..)
+            | Predicate::ConstEquate(..) => None,
         }
     }
 
@@ -1363,7 +1370,8 @@ pub fn to_opt_type_outlives(&self) -> Option<PolyTypeOutlivesPredicate<'tcx>> {
             | Predicate::WellFormed(..)
             | Predicate::ObjectSafe(..)
             | Predicate::ClosureKind(..)
-            | Predicate::ConstEvaluatable(..) => None,
+            | Predicate::ConstEvaluatable(..)
+            | Predicate::ConstEquate(..) => None,
         }
     }
 }
index afd670b85775b2de643c31cca6c93dda8ab3d06c..3e6a12df6887dd49416923986fb668abad80c5e8 100644 (file)
@@ -83,6 +83,11 @@ impl<'tcx> TyCtxt<'tcx> {
                 }
             }
 
+            ty::Array(element, _) => {
+                // Don't look into the len const as it doesn't affect regions
+                compute_components(tcx, element, out);
+            }
+
             ty::Closure(_, ref substs) => {
                 for upvar_ty in substs.as_closure().upvar_tys() {
                     compute_components(tcx, upvar_ty, out);
@@ -158,7 +163,6 @@ impl<'tcx> TyCtxt<'tcx> {
             ty::Opaque(..) |      // OutlivesNominalType (ish)
             ty::Foreign(..) |     // OutlivesNominalType
             ty::Str |             // OutlivesScalar (ish)
-            ty::Array(..) |       // ...
             ty::Slice(..) |       // ...
             ty::RawPtr(..) |      // ...
             ty::Ref(..) |         // OutlivesReference
index 64909cd0c467afb2d71a73280a4e8431c0a9e897..2502a4a13a8f0e7550658d00c33a17a7a0707ee9 100644 (file)
@@ -2058,6 +2058,13 @@ pub fn print_only_trait_path(self) -> ty::Binder<TraitRefPrintOnlyTraitPath<'tcx
                    print_value_path(def_id, substs),
                    write("` can be evaluated"))
             }
+            ty::Predicate::ConstEquate(c1, c2) => {
+                p!(write("the constant `"),
+                   print(c1),
+                   write("` equals `"),
+                   print(c2),
+                   write("`"))
+            }
         }
     }
 
index d68bc7221f92dd5e692daaea025edad1bff4fdac..0795990649f43777deaa9bc030069874d48ece74 100644 (file)
@@ -432,16 +432,17 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
             match relation.relate(&sz_a, &sz_b) {
                 Ok(sz) => Ok(tcx.mk_ty(ty::Array(t, sz))),
                 Err(err) => {
-                    // Check whether the lengths are both concrete/known values,
-                    // but are unequal, for better diagnostics.
-                    let sz_a = sz_a.try_eval_usize(tcx, relation.param_env());
-                    let sz_b = sz_b.try_eval_usize(tcx, relation.param_env());
-                    match (sz_a, sz_b) {
-                        (Some(sz_a_val), Some(sz_b_val)) => Err(TypeError::FixedArraySize(
-                            expected_found(relation, &sz_a_val, &sz_b_val),
-                        )),
-                        _ => Err(err),
-                    }
+                    //                    // Check whether the lengths are both concrete/known values,
+                    //                    // but are unequal, for better diagnostics.
+                    //                    let sz_a = sz_a.try_eval_usize(tcx, relation.param_env());
+                    //                    let sz_b = sz_b.try_eval_usize(tcx, relation.param_env());
+                    //                    match (sz_a, sz_b) {
+                    //                        (Some(sz_a_val), Some(sz_b_val)) => Err(TypeError::FixedArraySize(
+                    //                            expected_found(relation, &sz_a_val, &sz_b_val),
+                    //                        )),
+                    //                        _ => Err(err),
+                    //                    }
+                    Err(err)
                 }
             }
         }
@@ -604,14 +605,14 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
         }
 
         // FIXME(const_generics): this is wrong, as it is a projection
-        (
-            ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
-            ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
-        ) if a_def_id == b_def_id && a_promoted == b_promoted => {
-            let substs =
-                relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
-            Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
-        }
+        // (
+        //     ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
+        //     ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
+        // ) if a_def_id == b_def_id && a_promoted == b_promoted => {
+        //     let substs =
+        //         relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
+        //     Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
+        // }
         _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
     };
     new_const_val.map(|val| tcx.mk_const(ty::Const { val, ty: a.ty }))
index 680b718792199605cf420ffbaafdd4094ded0399..cdb7e34546af8999f3e2fd84f83f476174554925 100644 (file)
@@ -240,6 +240,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             ty::Predicate::ConstEvaluatable(def_id, substs) => {
                 write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
             }
+            ty::Predicate::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
         }
     }
 }
@@ -492,6 +493,9 @@ fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
             ty::Predicate::ConstEvaluatable(def_id, substs) => {
                 tcx.lift(&substs).map(|substs| ty::Predicate::ConstEvaluatable(def_id, substs))
             }
+            ty::Predicate::ConstEquate(c1, c2) => {
+                tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::Predicate::ConstEquate(c1, c2))
+            }
         }
     }
 }
index 96ae534c3963f16531812375b83fe9f7058a6d32..c3b0bd82398cb9ae911bd5fa8cab7fbb9ac16595 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::relate::TypeRelation;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Const, Ty};
 use rustc_trait_selection::traits::query::Fallible;
 
 use crate::borrow_check::constraints::OutlivesConstraint;
@@ -99,6 +99,8 @@ fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
         }
     }
 
+    fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
+
     fn normalization() -> NormalizationStrategy {
         NormalizationStrategy::Eager
     }
index c9982aeaa0839636c40b290b4e625627fc66dba9..a2e2c1bf9eda30e1dece280f9c82f4301732a36e 100644 (file)
@@ -28,7 +28,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
                 | Predicate::TypeOutlives(_)
                 | Predicate::WellFormed(_)
                 | Predicate::Projection(_)
-                | Predicate::ConstEvaluatable(..) => continue,
+                | Predicate::ConstEvaluatable(..)
+                | Predicate::ConstEquate(..) => continue,
                 Predicate::ObjectSafe(_) => {
                     bug!("object safe predicate on function: {:#?}", predicate)
                 }
index 4f8075b0171d33f32f163ce08a92def4c2126b61..396965fcfb8b790c63b5eedaaa694b8d3b897bbf 100644 (file)
@@ -1277,7 +1277,8 @@ pub fn may_define_opaque_type(
                 | ty::Predicate::ObjectSafe(..)
                 | ty::Predicate::ClosureKind(..)
                 | ty::Predicate::RegionOutlives(..)
-                | ty::Predicate::ConstEvaluatable(..) => None,
+                | ty::Predicate::ConstEvaluatable(..)
+                | ty::Predicate::ConstEquate(..) => None,
                 ty::Predicate::TypeOutlives(predicate) => {
                     // Search for a bound of the form `erased_self_ty
                     // : 'a`, but be wary of something like `for<'a>
index 0d53df3bf4b466ecba0500bc69560e8a7e498df8..1b8f2e1ae9fd41581e62321dec688594da2761e5 100644 (file)
@@ -615,6 +615,18 @@ fn report_selection_error(
                             obligation
                         )
                     }
+
+                    
+                    ty::Predicate::ConstEquate(..) => {
+                        // Errors for `ConstEquate` predicates show up as
+                        // `SelectionError::ConstEvalFailure`,
+                        // not `Unimplemented`.
+                        span_bug!(
+                            span,
+                            "const-equate requirement gave wrong error: `{:?}`",
+                            obligation
+                        )
+                    }
                 }
             }
 
@@ -1092,6 +1104,15 @@ fn report_fulfillment_error(
                 )
                 .emit();
             }
+            FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => {
+                self.report_mismatched_consts(
+                    &error.obligation.cause,
+                    expected_found.expected,
+                    expected_found.found,
+                    err.clone(),
+                )
+                .emit();
+            }
         }
     }
 
index 1e056c96acd383fd264f454927c9921064977253..18ba46dce23d38a809d6476ef57764a7b3a120ff 100644 (file)
@@ -3,8 +3,9 @@
 use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
 use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
+use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Const, ToPolyTraitRef, Ty, TypeFoldable};
 use std::marker::PhantomData;
 
 use super::project;
@@ -520,6 +521,65 @@ fn process_obligation(
                     Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))),
                 }
             }
+
+            ty::Predicate::ConstEquate(c1, c2) => {
+                debug!("equating consts: c1={:?} c2={:?}", c1, c2);
+
+                let stalled_on = &mut pending_obligation.stalled_on;
+
+                let mut evaluate = |c: &'tcx Const<'tcx>| {
+                    if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
+                        match self.selcx.infcx().const_eval_resolve(
+                            obligation.param_env,
+                            def_id,
+                            substs,
+                            promoted,
+                            Some(obligation.cause.span),
+                        ) {
+                            Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)),
+                            Err(ErrorHandled::TooGeneric) => {
+                                stalled_on.append(
+                                    &mut substs.types().filter_map(|ty| TyOrConstInferVar::maybe_from_ty(ty)).collect(),
+                                );
+                                Err(ProcessResult::Unchanged)
+                            }
+                            Err(err) => {
+                                Err(ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))))
+                            }
+                        }
+                    } else {
+                        Ok(c)
+                    }
+                };
+
+                match (evaluate(c1), evaluate(c2)) {
+                    (Ok(c1), Ok(c2)) => {
+                        match self
+                            .selcx
+                            .infcx()
+                            .at(&obligation.cause, obligation.param_env)
+                            .eq(c1, c2)
+                        {
+                            Ok(_) => ProcessResult::Changed(vec![]),
+                            Err(err) => {
+                                ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
+                                    ExpectedFound::new(true, c1, c2),
+                                    err,
+                                ))
+                            }
+                        }
+                    }
+                    // FIXME(skinny121) How to report both errors if both produces errors?
+                    (Err(result @ ProcessResult::Error(_)), _)
+                    | (_, Err(result @ ProcessResult::Error(_))) => result,
+                    (Err(ProcessResult::Unchanged), _) | (_, Err(ProcessResult::Unchanged)) => {
+                        ProcessResult::Unchanged
+                    }
+                    _ => {
+                        unreachable!("evaluate shouldn't itself return ProcessResult::Changed(..)")
+                    }
+                }
+            }
         }
     }
 
index 96b2b904e65436fe26709ffc06e8c388da38b5ef..3b4533b04ba4c19c4cbc7ca0d1935ad3d6cbb33c 100644 (file)
@@ -16,8 +16,8 @@
 use rustc_errors::{Applicability, FatalError};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
-use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
+use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
+use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -281,7 +281,8 @@ fn predicates_reference_self(
                 | ty::Predicate::RegionOutlives(..)
                 | ty::Predicate::ClosureKind(..)
                 | ty::Predicate::Subtype(..)
-                | ty::Predicate::ConstEvaluatable(..) => None,
+                | ty::Predicate::ConstEvaluatable(..)
+                | ty::Predicate::ConstEquate(..) => None,
             }
         })
         .collect()
@@ -313,7 +314,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         | ty::Predicate::ObjectSafe(..)
         | ty::Predicate::ClosureKind(..)
         | ty::Predicate::TypeOutlives(..)
-        | ty::Predicate::ConstEvaluatable(..) => false,
+        | ty::Predicate::ConstEvaluatable(..)
+        | ty::Predicate::ConstEquate(..) => false,
     })
 }
 
@@ -724,51 +726,65 @@ fn contains_illegal_self_type_reference<'tcx>(
     // object type, and we cannot resolve `Self as SomeOtherTrait`
     // without knowing what `Self` is.
 
-    let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
-    let self_ty = tcx.types.self_param;
-
-    let mut walker = ty.walk();
-    while let Some(arg) = walker.next() {
-        if arg == self_ty.into() {
-            return true;
-        }
-
-        // Special-case projections (everything else is walked normally).
-        if let GenericArgKind::Type(ty) = arg.unpack() {
-            if let ty::Projection(ref data) = ty.kind {
-                // This is a projected type `<Foo as SomeTrait>::X`.
+    struct IllegalSelfTypeVisitor<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        self_ty: Ty<'tcx>,
+        trait_def_id: DefId,
+        supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>>,
+    }
 
-                // Compute supertraits of current trait lazily.
-                if supertraits.is_none() {
-                    let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id));
-                    supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
-                }
+    impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+            match t.kind {
+                ty::Param(_) => t == self.self_ty,
+                ty::Projection(ref data) => {
+                    // This is a projected type `<Foo as SomeTrait>::X`.
+
+                    // Compute supertraits of current trait lazily.
+                    if self.supertraits.is_none() {
+                        let trait_ref =
+                            ty::Binder::bind(ty::TraitRef::identity(self.tcx, self.trait_def_id));
+                        self.supertraits = Some(traits::supertraits(self.tcx, trait_ref).collect());
+                    }
 
-                // Determine whether the trait reference `Foo as
-                // SomeTrait` is in fact a supertrait of the
-                // current trait. In that case, this type is
-                // legal, because the type `X` will be specified
-                // in the object type.  Note that we can just use
-                // direct equality here because all of these types
-                // are part of the formal parameter listing, and
-                // hence there should be no inference variables.
-                let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx));
-                let is_supertrait_of_current_trait =
-                    supertraits.as_ref().unwrap().contains(&projection_trait_ref);
-
-                if is_supertrait_of_current_trait {
-                    // Do not walk contained types, do not report error, do collect $200.
-                    walker.skip_current_subtree();
+                    // Determine whether the trait reference `Foo as
+                    // SomeTrait` is in fact a supertrait of the
+                    // current trait. In that case, this type is
+                    // legal, because the type `X` will be specified
+                    // in the object type.  Note that we can just use
+                    // direct equality here because all of these types
+                    // are part of the formal parameter listing, and
+                    // hence there should be no inference variables.
+                    let projection_trait_ref = ty::Binder::bind(data.trait_ref(self.tcx));
+                    let is_supertrait_of_current_trait =
+                        self.supertraits.as_ref().unwrap().contains(&projection_trait_ref);
+
+                    if is_supertrait_of_current_trait {
+                        false // do not walk contained types, do not report error, do collect $200
+                    } else {
+                        t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
+                    }
                 }
-
-                // DO walk contained types, POSSIBLY reporting an error.
+                _ => t.super_visit_with(self), // walk contained types, if any
             }
         }
 
-        // Walk contained types, if any.
+        fn visit_const(&mut self, _c: &ty::Const<'tcx>) -> bool {
+            // FIXME Look into the unevaluated constants for object safety violations.
+            // Do not walk substitutions of unevaluated consts, as they contain `Self`, even
+            // though the const expression doesn't necessary use it. Currently type variables
+            // inside array length expressions are forbidden, so they can't break the above
+            // rules.
+            false
+        }
     }
 
-    false
+    ty.visit_with(&mut IllegalSelfTypeVisitor {
+        tcx,
+        self_ty: tcx.types.self_param,
+        trait_def_id,
+        supertraits: None,
+    })
 }
 
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
index 0779882b6dd58145f6d0ce552b09ea13213f732f..d7402fc5376d682b294a59f84d539be492e10691 100644 (file)
@@ -386,11 +386,6 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             _ => ty,
         }
     }
-
-    fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        let constant = constant.super_fold_with(self);
-        constant.eval(self.selcx.tcx(), self.param_env)
-    }
 }
 
 /// The guts of `normalize`: normalize a specific projection like `<T
index 3b985a4b150faa7b447cb7b764d82b28ac805b46..c1150036ac2c019d4100663c8f58d58e182f7bdb 100644 (file)
@@ -201,9 +201,4 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             _ => ty,
         }
     }
-
-    fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        let constant = constant.super_fold_with(self);
-        constant.eval(self.infcx.tcx, self.param_env)
-    }
 }
index f0ff30232b96dea78c6e7ef88cae76afcddb4acd..4f4942ff596fc743c1e53f21ae87fba3182fdd63 100644 (file)
@@ -43,6 +43,7 @@
 use rustc_hir::lang_items;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
+use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::fast_reject;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
@@ -503,9 +504,43 @@ fn evaluate_predicate_recursively<'o>(
                     None,
                 ) {
                     Ok(_) => Ok(EvaluatedToOk),
+                    Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
                     Err(_) => Ok(EvaluatedToErr),
                 }
             }
+
+            ty::Predicate::ConstEquate(c1, c2) => {
+                debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2);
+
+                let evaluate = |c: &'tcx ty::Const<'tcx>| {
+                    if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
+                        match self.infcx.const_eval_resolve(
+                            obligation.param_env,
+                            def_id,
+                            substs,
+                            promoted,
+                            Some(obligation.cause.span),
+                        ) {
+                            Ok(val) => Ok(ty::Const::from_value(self.tcx(), val, c.ty)),
+                            Err(ErrorHandled::TooGeneric) => Err(EvaluatedToAmbig),
+                            Err(_) => Err(EvaluatedToErr),
+                        }
+                    } else {
+                        Ok(c)
+                    }
+                };
+
+                match (evaluate(c1), evaluate(c2)) {
+                    (Ok(c1), Ok(c2)) => {
+                        match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) {
+                            Ok(_) => Ok(EvaluatedToOk),
+                            Err(_) => Ok(EvaluatedToErr),
+                        }
+                    }
+                    (Err(EvaluatedToErr), _) | (_, Err(EvaluatedToErr)) => Ok(EvaluatedToErr),
+                    _ => Ok(EvaluatedToAmbig),
+                }
+            }
         }
     }
 
index ba7ec96775c047dd5688c55627480955dadd6987..4d3bbfa77c37d99e0088fb35f573b71952d23316 100644 (file)
@@ -102,6 +102,10 @@ pub fn predicate_obligations<'a, 'tcx>(
                 wf.compute(ty);
             }
         }
+        ty::Predicate::ConstEquate(c1, c2) => {
+            wf.compute(c1.ty);
+            wf.compute(c2.ty);
+        }
     }
 
     wf.normalize()
index 6db2e557fea694a05f29cb2897c06e710f56a993..eaaab87ab747467aa1952c653391b60458f04769 100644 (file)
@@ -100,7 +100,8 @@ fn compute_implied_outlives_bounds<'tcx>(
                 | ty::Predicate::Projection(..)
                 | ty::Predicate::ClosureKind(..)
                 | ty::Predicate::ObjectSafe(..)
-                | ty::Predicate::ConstEvaluatable(..) => vec![],
+                | ty::Predicate::ConstEvaluatable(..)
+                | ty::Predicate::ConstEquate(..) => vec![],
 
                 ty::Predicate::WellFormed(subty) => {
                     wf_types.push(subty);
index ad6c753edff00d63acbc0a96f197e135f3fce6ea..ed30ed5313e5c591ff3eca0df43cd70ea0c64c81 100644 (file)
@@ -48,6 +48,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool {
         | ty::Predicate::ObjectSafe(..)
         | ty::Predicate::ClosureKind(..)
         | ty::Predicate::Subtype(..)
-        | ty::Predicate::ConstEvaluatable(..) => true,
+        | ty::Predicate::ConstEvaluatable(..)
+        | ty::Predicate::ConstEquate(..) => true,
     }
 }
index 7f1d77e5b97d871dfc61377596b31f4c734e4c1d..e21db9035e25d11da0e565561fd774accf9c5404 100644 (file)
@@ -810,7 +810,8 @@ fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
             | ty::Predicate::ObjectSafe(..)
             | ty::Predicate::ClosureKind(..)
             | ty::Predicate::TypeOutlives(..)
-            | ty::Predicate::ConstEvaluatable(..) => None,
+            | ty::Predicate::ConstEvaluatable(..)
+            | ty::Predicate::ConstEquate(..) => None,
         });
 
         self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
index 6bf836015d226b6596885d95304c96388b544958..02b42284e6dea8a16b9867a28adfb62cd65a6a44 100644 (file)
@@ -1648,6 +1648,16 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
 
             r.super_visit_with(self)
         }
+
+        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
+            if let ty::ConstKind::Unevaluated(..) = c.val {
+                // FIXME(lazy_normalization_consts) We currenctly don't detect lifetimes within substs
+                // which would violate this check. Even though the particular substitution is not used
+                // within the const, this should still be fixed.
+                return false;
+            }
+            c.super_visit_with(self)
+        }
     }
 
     let prohibit_opaque = match item.kind {
@@ -3858,6 +3868,7 @@ fn obligations_for_self_ty<'b>(
                 ty::Predicate::WellFormed(..) => None,
                 ty::Predicate::ObjectSafe(..) => None,
                 ty::Predicate::ConstEvaluatable(..) => None,
+                ty::Predicate::ConstEquate(..) => None,
                 // N.B., this predicate is created by breaking down a
                 // `ClosureType: FnFoo()` predicate, where
                 // `ClosureType` represents some `Closure`. It can't
index 854bd03b2648679237144d5980f852b8bddf43c3..efee33fa5b930559d4b40358c06b54bfc07feb3c 100644 (file)
@@ -1156,7 +1156,8 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
 
     let node = tcx.hir().get(hir_id);
     let parent_def_id = match node {
-        Node::ImplItem(_)
+        Node::AnonConst(_)
+        | Node::ImplItem(_)
         | Node::TraitItem(_)
         | Node::Variant(_)
         | Node::Ctor(..)
@@ -1164,34 +1165,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             let parent_id = tcx.hir().get_parent_item(hir_id);
             Some(tcx.hir().local_def_id(parent_id).to_def_id())
         }
-        // FIXME(#43408) enable this always when we get lazy normalization.
-        Node::AnonConst(_) => {
-            let parent_id = tcx.hir().get_parent_item(hir_id);
-            let parent_def_id = tcx.hir().local_def_id(parent_id);
-
-            // HACK(eddyb) this provides the correct generics when
-            // `feature(const_generics)` is enabled, so that const expressions
-            // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
-            if tcx.features().const_generics {
-                Some(parent_def_id.to_def_id())
-            } else {
-                let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
-                match parent_node {
-                    // HACK(eddyb) this provides the correct generics for repeat
-                    // expressions' count (i.e. `N` in `[x; N]`), and explicit
-                    // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
-                    // as they shouldn't be able to cause query cycle errors.
-                    Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                    | Node::Variant(Variant { disr_expr: Some(ref constant), .. })
-                        if constant.hir_id == hir_id =>
-                    {
-                        Some(parent_def_id.to_def_id())
-                    }
 
-                    _ => None,
-                }
-            }
-        }
         Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
             Some(tcx.closure_base_def_id(def_id))
         }
index 8b12535b3a2cf2c57873f29a9319bca9c35ae26b..919bcc9943d4883920cd80890f51f5a158cab023 100644 (file)
@@ -413,6 +413,7 @@ fn trait_predicate_kind<'tcx>(
         | ty::Predicate::Subtype(_)
         | ty::Predicate::ObjectSafe(_)
         | ty::Predicate::ClosureKind(..)
-        | ty::Predicate::ConstEvaluatable(..) => None,
+        | ty::Predicate::ConstEvaluatable(..)
+        | ty::Predicate::ConstEquate(..) => None,
     }
 }
index 168f20771476c781838dbea2d885705cef3a1168..66daf0e7f7d9df6df31870c5f66743e7203c2153 100644 (file)
@@ -58,7 +58,8 @@ pub fn explicit_predicates_of(
                     | ty::Predicate::ObjectSafe(..)
                     | ty::Predicate::ClosureKind(..)
                     | ty::Predicate::Subtype(..)
-                    | ty::Predicate::ConstEvaluatable(..) => (),
+                    | ty::Predicate::ConstEvaluatable(..)
+                    | ty::Predicate::ConstEquate(..) => (),
                 }
             }
 
index 6c001bc548410670f9825e0d1920b9eae77e2f62..c130ed3f46dbb5d7916d1d2896e17c066a2a569a 100644 (file)
@@ -493,7 +493,8 @@ fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
             Predicate::WellFormed(..)
             | Predicate::ObjectSafe(..)
             | Predicate::ClosureKind(..)
-            | Predicate::ConstEvaluatable(..) => panic!("not user writable"),
+            | Predicate::ConstEvaluatable(..)
+            | Predicate::ConstEquate(..) => panic!("not user writable"),
         }
     }
 }