diff options
Diffstat (limited to 'compiler/rustc_middle/src/mir/interpret/queries.rs')
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/queries.rs | 80 |
1 files changed, 73 insertions, 7 deletions
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 8fc957cf49c..69353232f06 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,4 +1,4 @@ -use super::{ErrorHandled, EvalToConstValueResult, GlobalId}; +use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use crate::mir; use crate::ty::fold::TypeFoldable; @@ -11,6 +11,10 @@ impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts /// that can't take any generic arguments like statics, const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. + /// + /// Note: Returns a `ConstValue`, which isn't supposed to be used in the type system. In order to + /// evaluate to a type-system level constant value use `const_eval_poly_for_typeck`. + #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'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 @@ -23,6 +27,22 @@ impl<'tcx> TyCtxt<'tcx> { self.const_eval_global_id(param_env, cid, None) } + /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts + /// that can't take any generic arguments like statics, const items or enum discriminants. If a + /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. + #[instrument(skip(self), level = "debug")] + pub fn const_eval_poly_for_typeck(self, def_id: DefId) -> EvalToValTreeResult<'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 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_normalized(self); + self.const_eval_global_id_for_typeck(param_env, cid, None) + } + /// Resolves and evaluates a constant. /// /// The constant can be located on a trait like `<A as B>::C`, in which case the given @@ -59,6 +79,33 @@ impl<'tcx> TyCtxt<'tcx> { } } + #[instrument(level = "debug", skip(self))] + pub fn const_eval_resolve_for_typeck( + self, + param_env: ty::ParamEnv<'tcx>, + ct: ty::Unevaluated<'tcx>, + span: Option<Span>, + ) -> EvalToValTreeResult<'tcx> { + // Cannot resolve `Unevaluated` constants that contain inference + // variables. We reject those here since `resolve_opt_const_arg` + // would fail otherwise. + // + // When trying to evaluate constants containing inference variables, + // use `Infcx::const_eval_resolve` instead. + if ct.substs.has_infer_types_or_consts() { + bug!("did not expect inference variables here"); + } + + match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { + Ok(Some(instance)) => { + let cid = GlobalId { instance, promoted: ct.promoted }; + self.const_eval_global_id_for_typeck(param_env, cid, span) + } + Ok(None) => Err(ErrorHandled::TooGeneric), + Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), + } + } + pub fn const_eval_instance( self, param_env: ty::ParamEnv<'tcx>, @@ -68,7 +115,8 @@ impl<'tcx> TyCtxt<'tcx> { self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span) } - /// Evaluate a constant. + /// Evaluate a constant to a `ConstValue`. + #[instrument(skip(self), level = "debug")] pub fn const_eval_global_id( self, param_env: ty::ParamEnv<'tcx>, @@ -86,6 +134,27 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Evaluate a constant to a type-level constant. + #[instrument(skip(self), level = "debug")] + pub fn const_eval_global_id_for_typeck( + self, + param_env: ty::ParamEnv<'tcx>, + cid: GlobalId<'tcx>, + span: Option<Span>, + ) -> EvalToValTreeResult<'tcx> { + let param_env = param_env.with_const(); + debug!(?param_env); + // 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)); + debug!(?inputs); + if let Some(span) = span { + self.at(span).eval_to_valtree(inputs) + } else { + self.eval_to_valtree(inputs) + } + } + /// Evaluate a static's initializer, returning the allocation of the initializer's memory. #[inline(always)] pub fn eval_static_initializer( @@ -125,11 +194,8 @@ impl<'tcx> TyCtxtAt<'tcx> { impl<'tcx> TyCtxt<'tcx> { /// Destructure a type-level constant ADT or array into its variant index and its field values. /// Panics if the destructuring fails, use `try_destructure_const` for fallible version. - pub fn destructure_const( - self, - param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>, - ) -> mir::DestructuredConst<'tcx> { - self.try_destructure_const(param_env_and_val).unwrap() + pub fn destructure_const(self, const_: ty::Const<'tcx>) -> mir::DestructuredConst<'tcx> { + self.try_destructure_const(const_).unwrap() } /// Destructure a mir constant ADT or array into its variant index and its field values. |
