1 use super::{ErrorHandled, EvalToConstValueResult, GlobalId}
;
4 use crate::ty
::subst
::{InternalSubsts, SubstsRef}
;
5 use crate::ty
::{self, TyCtxt}
;
6 use rustc_hir
::def_id
::DefId
;
9 impl<'tcx
> TyCtxt
<'tcx
> {
10 /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
11 /// that can't take any generic arguments like statics, const items or enum discriminants. If a
12 /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
13 pub fn const_eval_poly(self, def_id
: DefId
) -> EvalToConstValueResult
<'tcx
> {
14 // In some situations def_id will have substitutions within scope, but they aren't allowed
15 // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
16 // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
18 let substs
= InternalSubsts
::identity_for_item(self, def_id
);
19 let instance
= ty
::Instance
::new(def_id
, substs
);
20 let cid
= GlobalId { instance, promoted: None }
;
21 let param_env
= self.param_env(def_id
).with_reveal_all_normalized(self);
22 self.const_eval_global_id(param_env
, cid
, None
)
25 /// Resolves and evaluates a constant.
27 /// The constant can be located on a trait like `<A as B>::C`, in which case the given
28 /// substitutions and environment are used to resolve the constant. Alternatively if the
29 /// constant has generic parameters in scope the substitutions are used to evaluate the value of
30 /// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
31 /// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
32 /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
34 #[instrument(level = "debug", skip(self))]
35 pub fn const_eval_resolve(
37 param_env
: ty
::ParamEnv
<'tcx
>,
38 def
: ty
::WithOptConstParam
<DefId
>,
39 substs
: SubstsRef
<'tcx
>,
40 promoted
: Option
<mir
::Promoted
>,
42 ) -> EvalToConstValueResult
<'tcx
> {
43 match ty
::Instance
::resolve_opt_const_arg(self, param_env
, def
, substs
) {
44 Ok(Some(instance
)) => {
45 let cid
= GlobalId { instance, promoted }
;
46 self.const_eval_global_id(param_env
, cid
, span
)
48 Ok(None
) => Err(ErrorHandled
::TooGeneric
),
49 Err(error_reported
) => Err(ErrorHandled
::Reported(error_reported
)),
53 pub fn const_eval_instance(
55 param_env
: ty
::ParamEnv
<'tcx
>,
56 instance
: ty
::Instance
<'tcx
>,
58 ) -> EvalToConstValueResult
<'tcx
> {
59 self.const_eval_global_id(param_env
, GlobalId { instance, promoted: None }
, span
)
62 /// Evaluate a constant.
63 pub fn const_eval_global_id(
65 param_env
: ty
::ParamEnv
<'tcx
>,
68 ) -> EvalToConstValueResult
<'tcx
> {
69 // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
70 // improve caching of queries.
71 let inputs
= self.erase_regions(param_env
.and(cid
));
72 if let Some(span
) = span
{
73 self.at(span
).eval_to_const_value_raw(inputs
)
75 self.eval_to_const_value_raw(inputs
)
79 /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
80 pub fn eval_static_initializer(
83 ) -> Result
<&'tcx mir
::Allocation
, ErrorHandled
> {
84 trace
!("eval_static_initializer: Need to compute {:?}", def_id
);
85 assert
!(self.is_static(def_id
));
86 let instance
= ty
::Instance
::mono(self, def_id
);
87 let gid
= GlobalId { instance, promoted: None }
;
88 self.eval_to_allocation(gid
, ty
::ParamEnv
::reveal_all())
91 /// Evaluate anything constant-like, returning the allocation of the final memory.
92 fn eval_to_allocation(
95 param_env
: ty
::ParamEnv
<'tcx
>,
96 ) -> Result
<&'tcx mir
::Allocation
, ErrorHandled
> {
97 trace
!("eval_to_allocation: Need to compute {:?}", gid
);
98 let raw_const
= self.eval_to_allocation_raw(param_env
.and(gid
))?
;
99 Ok(self.global_alloc(raw_const
.alloc_id
).unwrap_memory())