1 use std
::convert
::TryInto
;
3 use crate::mir
::interpret
::ConstValue
;
4 use crate::mir
::interpret
::Scalar
;
5 use crate::mir
::Promoted
;
6 use crate::ty
::subst
::{InternalSubsts, SubstsRef}
;
7 use crate::ty
::ParamEnv
;
8 use crate::ty
::{self, TyCtxt, TypeFoldable}
;
9 use rustc_errors
::ErrorReported
;
10 use rustc_hir
::def_id
::DefId
;
11 use rustc_macros
::HashStable
;
12 use rustc_target
::abi
::Size
;
16 /// Represents a constant in Rust.
17 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
19 pub enum ConstKind
<'tcx
> {
20 /// A const generic parameter.
21 Param(ty
::ParamConst
),
23 /// Infer the value of the const.
24 Infer(InferConst
<'tcx
>),
26 /// Bound const variable, used only when preparing a trait query.
27 Bound(ty
::DebruijnIndex
, ty
::BoundVar
),
29 /// A placeholder const - universally quantified higher-ranked const.
30 Placeholder(ty
::PlaceholderConst
<'tcx
>),
32 /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
33 /// variants when the code is monomorphic enough for that.
34 Unevaluated(ty
::WithOptConstParam
<DefId
>, SubstsRef
<'tcx
>, Option
<Promoted
>),
36 /// Used to hold computed value.
37 Value(ConstValue
<'tcx
>),
39 /// A placeholder for a const which could not be computed; this is
40 /// propagated to avoid useless error messages.
41 Error(ty
::DelaySpanBugEmitted
),
44 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
45 static_assert_size
!(ConstKind
<'_
>, 40);
47 impl<'tcx
> ConstKind
<'tcx
> {
49 pub fn try_to_value(self) -> Option
<ConstValue
<'tcx
>> {
50 if let ConstKind
::Value(val
) = self { Some(val) }
else { None }
54 pub fn try_to_scalar(self) -> Option
<Scalar
> {
55 self.try_to_value()?
.try_to_scalar()
59 pub fn try_to_scalar_int(self) -> Option
<ScalarInt
> {
60 Some(self.try_to_value()?
.try_to_scalar()?
.assert_int())
64 pub fn try_to_bits(self, size
: Size
) -> Option
<u128
> {
65 self.try_to_scalar_int()?
.to_bits(size
).ok()
69 pub fn try_to_bool(self) -> Option
<bool
> {
70 self.try_to_scalar_int()?
.try_into().ok()
74 pub fn try_to_machine_usize(self, tcx
: TyCtxt
<'tcx
>) -> Option
<u64> {
75 self.try_to_value()?
.try_to_machine_usize(tcx
)
79 /// An inference variable for a const, for use in const generics.
80 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
82 pub enum InferConst
<'tcx
> {
83 /// Infer the value of the const.
84 Var(ty
::ConstVid
<'tcx
>),
85 /// A fresh const variable. See `infer::freshen` for more details.
89 impl<'tcx
> ConstKind
<'tcx
> {
91 /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
92 /// unevaluated constant.
93 pub fn eval(self, tcx
: TyCtxt
<'tcx
>, param_env
: ParamEnv
<'tcx
>) -> Self {
94 self.try_eval(tcx
, param_env
).and_then(Result
::ok
).map_or(self, ConstKind
::Value
)
98 /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
100 pub(super) fn try_eval(
103 param_env
: ParamEnv
<'tcx
>,
104 ) -> Option
<Result
<ConstValue
<'tcx
>, ErrorReported
>> {
105 if let ConstKind
::Unevaluated(def
, substs
, promoted
) = self {
106 use crate::mir
::interpret
::ErrorHandled
;
108 // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
109 // also does later, but we want to do it before checking for
110 // inference variables.
111 // Note that we erase regions *before* calling `with_reveal_all_normalized`,
112 // so that we don't try to invoke this query with
113 // any region variables.
114 let param_env_and_substs
= tcx
115 .erase_regions(param_env
)
116 .with_reveal_all_normalized(tcx
)
117 .and(tcx
.erase_regions(substs
));
119 // HACK(eddyb) when the query key would contain inference variables,
120 // attempt using identity substs and `ParamEnv` instead, that will succeed
121 // when the expression doesn't depend on any parameters.
122 // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
123 // we can call `infcx.const_eval_resolve` which handles inference variables.
124 let param_env_and_substs
= if param_env_and_substs
.needs_infer() {
125 tcx
.param_env(def
.did
).and(InternalSubsts
::identity_for_item(tcx
, def
.did
))
130 // FIXME(eddyb) maybe the `const_eval_*` methods should take
131 // `ty::ParamEnvAnd<SubstsRef>` instead of having them separate.
132 let (param_env
, substs
) = param_env_and_substs
.into_parts();
133 // try to resolve e.g. associated constants to their definition on an impl, and then
134 // evaluate the const.
135 match tcx
.const_eval_resolve(param_env
, def
, substs
, promoted
, None
) {
136 // NOTE(eddyb) `val` contains no lifetimes/types/consts,
137 // and we use the original type, so nothing from `substs`
138 // (which may be identity substs, see above),
139 // can leak through `val` into the const we return.
140 Ok(val
) => Some(Ok(val
)),
141 Err(ErrorHandled
::TooGeneric
| ErrorHandled
::Linted
) => None
,
142 Err(ErrorHandled
::Reported(e
)) => Some(Err(e
)),