3 use crate::mir
::interpret
::{AllocId, ConstValue, Scalar}
;
4 use crate::ty
::abstract_const
::CastKind
;
5 use crate::ty
::subst
::{InternalSubsts, SubstsRef}
;
6 use crate::ty
::ParamEnv
;
7 use crate::ty
::{self, List, Ty, TyCtxt, TypeVisitableExt}
;
8 use rustc_data_structures
::stable_hasher
::{HashStable, StableHasher}
;
9 use rustc_errors
::ErrorGuaranteed
;
10 use rustc_hir
::def_id
::DefId
;
11 use rustc_macros
::HashStable
;
12 use rustc_target
::abi
::Size
;
16 /// An unevaluated (potentially generic) constant used in the type-system.
17 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
18 #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
19 pub struct UnevaluatedConst
<'tcx
> {
20 pub def
: ty
::WithOptConstParam
<DefId
>,
21 pub substs
: SubstsRef
<'tcx
>,
24 impl rustc_errors
::IntoDiagnosticArg
for UnevaluatedConst
<'_
> {
25 fn into_diagnostic_arg(self) -> rustc_errors
::DiagnosticArgValue
<'
static> {
26 format
!("{:?}", self).into_diagnostic_arg()
30 impl<'tcx
> UnevaluatedConst
<'tcx
> {
32 pub fn expand(self) -> mir
::UnevaluatedConst
<'tcx
> {
33 mir
::UnevaluatedConst { def: self.def, substs: self.substs, promoted: None }
37 impl<'tcx
> UnevaluatedConst
<'tcx
> {
40 def
: ty
::WithOptConstParam
<DefId
>,
41 substs
: SubstsRef
<'tcx
>,
42 ) -> UnevaluatedConst
<'tcx
> {
43 UnevaluatedConst { def, substs }
47 /// Represents a constant in Rust.
48 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
49 #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
50 #[derive(derive_more::From)]
51 pub enum ConstKind
<'tcx
> {
52 /// A const generic parameter.
53 Param(ty
::ParamConst
),
55 /// Infer the value of the const.
56 Infer(InferConst
<'tcx
>),
58 /// Bound const variable, used only when preparing a trait query.
59 Bound(ty
::DebruijnIndex
, ty
::BoundVar
),
61 /// A placeholder const - universally quantified higher-ranked const.
62 Placeholder(ty
::PlaceholderConst
<'tcx
>),
64 /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
65 /// variants when the code is monomorphic enough for that.
66 Unevaluated(UnevaluatedConst
<'tcx
>),
68 /// Used to hold computed value.
69 Value(ty
::ValTree
<'tcx
>),
71 /// A placeholder for a const which could not be computed; this is
72 /// propagated to avoid useless error messages.
74 Error(ErrorGuaranteed
),
76 /// Expr which contains an expression which has partially evaluated items.
80 impl<'tcx
> From
<ty
::ConstVid
<'tcx
>> for ConstKind
<'tcx
> {
81 fn from(const_vid
: ty
::ConstVid
<'tcx
>) -> Self {
82 InferConst
::Var(const_vid
).into()
86 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
87 #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
89 Binop(mir
::BinOp
, Const
<'tcx
>, Const
<'tcx
>),
90 UnOp(mir
::UnOp
, Const
<'tcx
>),
91 FunctionCall(Const
<'tcx
>, &'tcx List
<Const
<'tcx
>>),
92 Cast(CastKind
, Const
<'tcx
>, Ty
<'tcx
>),
95 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
96 static_assert_size
!(Expr
<'_
>, 24);
98 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
99 static_assert_size
!(ConstKind
<'_
>, 32);
101 impl<'tcx
> ConstKind
<'tcx
> {
103 pub fn try_to_value(self) -> Option
<ty
::ValTree
<'tcx
>> {
104 if let ConstKind
::Value(val
) = self { Some(val) }
else { None }
108 pub fn try_to_scalar(self) -> Option
<Scalar
<AllocId
>> {
109 self.try_to_value()?
.try_to_scalar()
113 pub fn try_to_scalar_int(self) -> Option
<ScalarInt
> {
114 self.try_to_value()?
.try_to_scalar_int()
118 pub fn try_to_bits(self, size
: Size
) -> Option
<u128
> {
119 self.try_to_scalar_int()?
.to_bits(size
).ok()
123 pub fn try_to_bool(self) -> Option
<bool
> {
124 self.try_to_scalar_int()?
.try_into().ok()
128 pub fn try_to_target_usize(self, tcx
: TyCtxt
<'tcx
>) -> Option
<u64> {
129 self.try_to_value()?
.try_to_target_usize(tcx
)
133 /// An inference variable for a const, for use in const generics.
134 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
135 pub enum InferConst
<'tcx
> {
136 /// Infer the value of the const.
137 Var(ty
::ConstVid
<'tcx
>),
138 /// A fresh const variable. See `infer::freshen` for more details.
142 impl<CTX
> HashStable
<CTX
> for InferConst
<'_
> {
143 fn hash_stable(&self, hcx
: &mut CTX
, hasher
: &mut StableHasher
) {
145 InferConst
::Var(_
) => panic
!("const variables should not be hashed: {self:?}"),
146 InferConst
::Fresh(i
) => i
.hash_stable(hcx
, hasher
),
156 enum EvalResult
<'tcx
> {
157 ValTree(ty
::ValTree
<'tcx
>),
158 ConstVal(ConstValue
<'tcx
>),
161 impl<'tcx
> ConstKind
<'tcx
> {
163 /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
164 /// unevaluated constant.
165 pub fn eval(self, tcx
: TyCtxt
<'tcx
>, param_env
: ParamEnv
<'tcx
>) -> Self {
166 self.try_eval_for_typeck(tcx
, param_env
).and_then(Result
::ok
).map_or(self, ConstKind
::Value
)
170 /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
172 // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
173 pub fn try_eval_for_mir(
176 param_env
: ParamEnv
<'tcx
>,
177 ) -> Option
<Result
<ConstValue
<'tcx
>, ErrorGuaranteed
>> {
178 match self.try_eval_inner(tcx
, param_env
, EvalMode
::Mir
) {
179 Some(Ok(EvalResult
::ValTree(_
))) => unreachable
!(),
180 Some(Ok(EvalResult
::ConstVal(v
))) => Some(Ok(v
)),
181 Some(Err(e
)) => Some(Err(e
)),
187 /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
189 // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
190 pub fn try_eval_for_typeck(
193 param_env
: ParamEnv
<'tcx
>,
194 ) -> Option
<Result
<ty
::ValTree
<'tcx
>, ErrorGuaranteed
>> {
195 match self.try_eval_inner(tcx
, param_env
, EvalMode
::Typeck
) {
196 Some(Ok(EvalResult
::ValTree(v
))) => Some(Ok(v
)),
197 Some(Ok(EvalResult
::ConstVal(_
))) => unreachable
!(),
198 Some(Err(e
)) => Some(Err(e
)),
207 param_env
: ParamEnv
<'tcx
>,
209 ) -> Option
<Result
<EvalResult
<'tcx
>, ErrorGuaranteed
>> {
210 assert
!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
211 if let ConstKind
::Unevaluated(unevaluated
) = self {
212 use crate::mir
::interpret
::ErrorHandled
;
214 // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
215 // also does later, but we want to do it before checking for
216 // inference variables.
217 // Note that we erase regions *before* calling `with_reveal_all_normalized`,
218 // so that we don't try to invoke this query with
219 // any region variables.
221 // HACK(eddyb) when the query key would contain inference variables,
222 // attempt using identity substs and `ParamEnv` instead, that will succeed
223 // when the expression doesn't depend on any parameters.
224 // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
225 // we can call `infcx.const_eval_resolve` which handles inference variables.
226 let param_env_and
= if (param_env
, unevaluated
).has_non_region_infer() {
227 tcx
.param_env(unevaluated
.def
.did
).and(ty
::UnevaluatedConst
{
228 def
: unevaluated
.def
,
229 substs
: InternalSubsts
::identity_for_item(tcx
, unevaluated
.def
.did
),
232 tcx
.erase_regions(param_env
)
233 .with_reveal_all_normalized(tcx
)
234 .and(tcx
.erase_regions(unevaluated
))
237 // FIXME(eddyb) maybe the `const_eval_*` methods should take
238 // `ty::ParamEnvAnd` instead of having them separate.
239 let (param_env
, unevaluated
) = param_env_and
.into_parts();
240 // try to resolve e.g. associated constants to their definition on an impl, and then
241 // evaluate the const.
243 EvalMode
::Typeck
=> {
244 match tcx
.const_eval_resolve_for_typeck(param_env
, unevaluated
, None
) {
245 // NOTE(eddyb) `val` contains no lifetimes/types/consts,
246 // and we use the original type, so nothing from `substs`
247 // (which may be identity substs, see above),
248 // can leak through `val` into the const we return.
249 Ok(val
) => Some(Ok(EvalResult
::ValTree(val?
))),
250 Err(ErrorHandled
::TooGeneric
) => None
,
251 Err(ErrorHandled
::Reported(e
)) => Some(Err(e
)),
255 match tcx
.const_eval_resolve(param_env
, unevaluated
.expand(), None
) {
256 // NOTE(eddyb) `val` contains no lifetimes/types/consts,
257 // and we use the original type, so nothing from `substs`
258 // (which may be identity substs, see above),
259 // can leak through `val` into the const we return.
260 Ok(val
) => Some(Ok(EvalResult
::ConstVal(val
))),
261 Err(ErrorHandled
::TooGeneric
) => None
,
262 Err(ErrorHandled
::Reported(e
)) => Some(Err(e
)),