about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/mir/interpret/queries.rs36
-rw-r--r--src/librustc/query/mod.rs2
-rw-r--r--src/librustc/ty/sty.rs4
-rw-r--r--src/librustc_infer/infer/mod.rs32
-rw-r--r--src/librustc_infer/traits/fulfill.rs30
-rw-r--r--src/librustc_infer/traits/select.rs23
-rw-r--r--src/librustc_mir/interpret/eval_context.rs6
-rw-r--r--src/test/incremental/const-generics/issue-68477.rs23
8 files changed, 94 insertions, 62 deletions
diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs
index ed57f81e782..46bf1d96957 100644
--- a/src/librustc/mir/interpret/queries.rs
+++ b/src/librustc/mir/interpret/queries.rs
@@ -13,13 +13,13 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> {
         // In some situations def_id will have substitutions within scope, but they aren't allowed
         // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
-        // into `const_eval` which will return `ErrorHandled::ToGeneric` if any og them are
+        // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
         // encountered.
         let substs = InternalSubsts::identity_for_item(self, def_id);
         let instance = ty::Instance::new(def_id, substs);
         let cid = GlobalId { instance, promoted: None };
         let param_env = self.param_env(def_id).with_reveal_all();
-        self.const_eval_validated(param_env.and(cid))
+        self.const_eval_global_id(param_env, cid, None)
     }
 
     /// Resolves and evaluates a constant.
@@ -41,11 +41,8 @@ impl<'tcx> TyCtxt<'tcx> {
     ) -> ConstEvalResult<'tcx> {
         let instance = ty::Instance::resolve(self, param_env, def_id, substs);
         if let Some(instance) = instance {
-            if let Some(promoted) = promoted {
-                self.const_eval_promoted(param_env, instance, promoted)
-            } else {
-                self.const_eval_instance(param_env, instance, span)
-            }
+            let cid = GlobalId { instance, promoted };
+            self.const_eval_global_id(param_env, cid, span)
         } else {
             Err(ErrorHandled::TooGeneric)
         }
@@ -57,22 +54,23 @@ impl<'tcx> TyCtxt<'tcx> {
         instance: ty::Instance<'tcx>,
         span: Option<Span>,
     ) -> ConstEvalResult<'tcx> {
-        let cid = GlobalId { instance, promoted: None };
-        if let Some(span) = span {
-            self.at(span).const_eval_validated(param_env.and(cid))
-        } else {
-            self.const_eval_validated(param_env.and(cid))
-        }
+        self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span)
     }
 
-    /// Evaluate a promoted constant.
-    pub fn const_eval_promoted(
+    /// Evaluate a constant.
+    pub fn const_eval_global_id(
         self,
         param_env: ty::ParamEnv<'tcx>,
-        instance: ty::Instance<'tcx>,
-        promoted: mir::Promoted,
+        cid: GlobalId<'tcx>,
+        span: Option<Span>,
     ) -> ConstEvalResult<'tcx> {
-        let cid = GlobalId { instance, promoted: Some(promoted) };
-        self.const_eval_validated(param_env.and(cid))
+        // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
+        // improve caching of queries.
+        let inputs = self.erase_regions(&param_env.and(cid));
+        if let Some(span) = span {
+            self.at(span).const_eval_validated(inputs)
+        } else {
+            self.const_eval_validated(inputs)
+        }
     }
 }
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 3a6961660fd..69698eabac4 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -513,7 +513,7 @@ rustc_queries! {
         /// returns a proper constant that is usable by the rest of the compiler.
         ///
         /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
-        /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_promoted`.
+        /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`.
         query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
             -> ConstEvalResult<'tcx> {
             no_force
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index c3698f402a9..283333b6a3d 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -2484,8 +2484,8 @@ impl<'tcx> Const<'tcx> {
                 // HACK(eddyb) when substs contain e.g. inference variables,
                 // attempt using identity substs instead, that will succeed
                 // when the expression doesn't depend on any parameters.
-                // FIXME(eddyb) make `const_eval` a canonical query instead,
-                // that would properly handle inference variables in `substs`.
+                // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
+                // we can call `infcx.const_eval_resolve` which handles inference variables.
                 if substs.has_local_value() {
                     let identity_substs = InternalSubsts::identity_for_item(tcx, did);
                     // The `ParamEnv` needs to match the `identity_substs`.
diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs
index 65f060deb46..26998f0a33c 100644
--- a/src/librustc_infer/infer/mod.rs
+++ b/src/librustc_infer/infer/mod.rs
@@ -15,6 +15,8 @@ use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToTy
 use rustc::middle::free_region::RegionRelations;
 use rustc::middle::lang_items;
 use rustc::middle::region;
+use rustc::mir;
+use rustc::mir::interpret::ConstEvalResult;
 use rustc::session::config::BorrowckMode;
 use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use rustc::ty::fold::{TypeFoldable, TypeFolder};
@@ -63,6 +65,7 @@ pub mod resolve;
 mod sub;
 pub mod type_variable;
 
+use crate::infer::canonical::OriginalQueryValues;
 pub use rustc::infer::unify_key;
 
 #[must_use]
@@ -1563,6 +1566,35 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.universe.set(u);
         u
     }
+
+    /// Resolves and evaluates a constant.
+    ///
+    /// The constant can be located on a trait like `<A as B>::C`, in which case the given
+    /// substitutions and environment are used to resolve the constant. Alternatively if the
+    /// constant has generic parameters in scope the substitutions are used to evaluate the value of
+    /// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
+    /// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
+    /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
+    /// returned.
+    ///
+    /// This handles inferences variables within both `param_env` and `substs` by
+    /// performing the operation on their respective canonical forms.
+    pub fn const_eval_resolve(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+        promoted: Option<mir::Promoted>,
+        span: Option<Span>,
+    ) -> ConstEvalResult<'tcx> {
+        let mut original_values = OriginalQueryValues::default();
+        let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values);
+
+        let (param_env, substs) = canonical.value;
+        // The return value is the evaluated value which doesn't contain any reference to inference
+        // variables, thus we don't need to substitute back the original values.
+        self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, span)
+    }
 }
 
 pub struct ShallowResolver<'a, 'tcx> {
diff --git a/src/librustc_infer/traits/fulfill.rs b/src/librustc_infer/traits/fulfill.rs
index 6055b0e74df..28d3f269180 100644
--- a/src/librustc_infer/traits/fulfill.rs
+++ b/src/librustc_infer/traits/fulfill.rs
@@ -510,27 +510,15 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
             }
 
             ty::Predicate::ConstEvaluatable(def_id, substs) => {
-                if obligation.param_env.has_local_value() {
-                    ProcessResult::Unchanged
-                } else {
-                    if !substs.has_local_value() {
-                        match self.selcx.tcx().const_eval_resolve(
-                            obligation.param_env,
-                            def_id,
-                            substs,
-                            None,
-                            Some(obligation.cause.span),
-                        ) {
-                            Ok(_) => ProcessResult::Changed(vec![]),
-                            Err(err) => {
-                                ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err)))
-                            }
-                        }
-                    } else {
-                        pending_obligation.stalled_on =
-                            substs.types().map(|ty| infer_ty(ty)).collect();
-                        ProcessResult::Unchanged
-                    }
+                match self.selcx.infcx().const_eval_resolve(
+                    obligation.param_env,
+                    def_id,
+                    substs,
+                    None,
+                    Some(obligation.cause.span),
+                ) {
+                    Ok(_) => ProcessResult::Changed(vec![]),
+                    Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))),
                 }
             }
         }
diff --git a/src/librustc_infer/traits/select.rs b/src/librustc_infer/traits/select.rs
index 4eac89138f1..c6878fad2a4 100644
--- a/src/librustc_infer/traits/select.rs
+++ b/src/librustc_infer/traits/select.rs
@@ -532,20 +532,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             ty::Predicate::ConstEvaluatable(def_id, substs) => {
-                if !(obligation.param_env, substs).has_local_value() {
-                    match self.tcx().const_eval_resolve(
-                        obligation.param_env,
-                        def_id,
-                        substs,
-                        None,
-                        None,
-                    ) {
-                        Ok(_) => Ok(EvaluatedToOk),
-                        Err(_) => Ok(EvaluatedToErr),
-                    }
-                } else {
-                    // Inference variables still left in param_env or substs.
-                    Ok(EvaluatedToAmbig)
+                match self.tcx().const_eval_resolve(
+                    obligation.param_env,
+                    def_id,
+                    substs,
+                    None,
+                    None,
+                ) {
+                    Ok(_) => Ok(EvaluatedToOk),
+                    Err(_) => Ok(EvaluatedToErr),
                 }
             }
         }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index fc4ba4d6cd9..cce4b90e224 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -768,11 +768,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         } else {
             self.param_env
         };
-        let val = if let Some(promoted) = gid.promoted {
-            self.tcx.const_eval_promoted(param_env, gid.instance, promoted)?
-        } else {
-            self.tcx.const_eval_instance(param_env, gid.instance, Some(self.tcx.span))?
-        };
+        let val = self.tcx.const_eval_global_id(param_env, gid, Some(self.tcx.span))?;
 
         // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a
         // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not
diff --git a/src/test/incremental/const-generics/issue-68477.rs b/src/test/incremental/const-generics/issue-68477.rs
new file mode 100644
index 00000000000..925931bc4a6
--- /dev/null
+++ b/src/test/incremental/const-generics/issue-68477.rs
@@ -0,0 +1,23 @@
+// edition:2018
+// revisions:rpass1
+#![feature(const_generics)]
+
+const FOO: usize = 1;
+
+struct Container<T> {
+    val: std::marker::PhantomData<T>,
+    blah: [(); FOO]
+}
+
+async fn dummy() {}
+
+async fn foo() {
+    let a: Container<&'static ()>;
+    dummy().await;
+}
+
+fn is_send<T: Send>(_: T) {}
+
+fn main() {
+    is_send(foo());
+}