]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/ty/consts/kind.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / consts / kind.rs
CommitLineData
6a06907d
XL
1use std::convert::TryInto;
2
136023e0 3use crate::mir::interpret::{AllocId, ConstValue, Scalar};
3dfed10e
XL
4use crate::mir::Promoted;
5use crate::ty::subst::{InternalSubsts, SubstsRef};
6use crate::ty::ParamEnv;
7use crate::ty::{self, TyCtxt, TypeFoldable};
5e7ed085 8use rustc_errors::ErrorGuaranteed;
3dfed10e
XL
9use rustc_hir::def_id::DefId;
10use rustc_macros::HashStable;
11use rustc_target::abi::Size;
12
6a06907d 13use super::ScalarInt;
cdc7bbd5 14/// An unevaluated, potentially generic, constant.
94222f64 15#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
cdc7bbd5 16#[derive(Hash, HashStable)]
94222f64 17pub struct Unevaluated<'tcx, P = Option<Promoted>> {
cdc7bbd5 18 pub def: ty::WithOptConstParam<DefId>,
5099ac24 19 pub substs: SubstsRef<'tcx>,
94222f64
XL
20 pub promoted: P,
21}
22
23impl<'tcx> Unevaluated<'tcx> {
24 #[inline]
25 pub fn shrink(self) -> Unevaluated<'tcx, ()> {
26 debug_assert_eq!(self.promoted, None);
5099ac24 27 Unevaluated { def: self.def, substs: self.substs, promoted: () }
94222f64
XL
28 }
29}
30
31impl<'tcx> Unevaluated<'tcx, ()> {
32 #[inline]
33 pub fn expand(self) -> Unevaluated<'tcx> {
5099ac24 34 Unevaluated { def: self.def, substs: self.substs, promoted: None }
94222f64
XL
35 }
36}
37
38impl<'tcx, P: Default> Unevaluated<'tcx, P> {
39 #[inline]
40 pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> {
5099ac24 41 Unevaluated { def, substs, promoted: Default::default() }
94222f64 42 }
cdc7bbd5 43}
6a06907d 44
3dfed10e 45/// Represents a constant in Rust.
cdc7bbd5
XL
46#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
47#[derive(Hash, HashStable)]
3dfed10e
XL
48pub enum ConstKind<'tcx> {
49 /// A const generic parameter.
50 Param(ty::ParamConst),
51
52 /// Infer the value of the const.
53 Infer(InferConst<'tcx>),
54
55 /// Bound const variable, used only when preparing a trait query.
56 Bound(ty::DebruijnIndex, ty::BoundVar),
57
58 /// A placeholder const - universally quantified higher-ranked const.
fc512014 59 Placeholder(ty::PlaceholderConst<'tcx>),
3dfed10e
XL
60
61 /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
62 /// variants when the code is monomorphic enough for that.
cdc7bbd5 63 Unevaluated(Unevaluated<'tcx>),
3dfed10e
XL
64
65 /// Used to hold computed value.
923072b8 66 Value(ty::ValTree<'tcx>),
3dfed10e
XL
67
68 /// A placeholder for a const which could not be computed; this is
69 /// propagated to avoid useless error messages.
70 Error(ty::DelaySpanBugEmitted),
71}
72
6a06907d 73#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
3dfed10e
XL
74static_assert_size!(ConstKind<'_>, 40);
75
76impl<'tcx> ConstKind<'tcx> {
77 #[inline]
923072b8 78 pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
3dfed10e
XL
79 if let ConstKind::Value(val) = self { Some(val) } else { None }
80 }
81
82 #[inline]
136023e0 83 pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
3dfed10e
XL
84 self.try_to_value()?.try_to_scalar()
85 }
86
6a06907d
XL
87 #[inline]
88 pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
923072b8 89 self.try_to_value()?.try_to_scalar_int()
6a06907d
XL
90 }
91
3dfed10e
XL
92 #[inline]
93 pub fn try_to_bits(self, size: Size) -> Option<u128> {
6a06907d 94 self.try_to_scalar_int()?.to_bits(size).ok()
3dfed10e
XL
95 }
96
97 #[inline]
98 pub fn try_to_bool(self) -> Option<bool> {
6a06907d 99 self.try_to_scalar_int()?.try_into().ok()
3dfed10e
XL
100 }
101
102 #[inline]
103 pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
104 self.try_to_value()?.try_to_machine_usize(tcx)
105 }
106}
107
108/// An inference variable for a const, for use in const generics.
109#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
110#[derive(HashStable)]
111pub enum InferConst<'tcx> {
112 /// Infer the value of the const.
113 Var(ty::ConstVid<'tcx>),
114 /// A fresh const variable. See `infer::freshen` for more details.
115 Fresh(u32),
116}
117
923072b8
FG
118enum EvalMode {
119 Typeck,
120 Mir,
121}
122
123enum EvalResult<'tcx> {
124 ValTree(ty::ValTree<'tcx>),
125 ConstVal(ConstValue<'tcx>),
126}
127
3dfed10e
XL
128impl<'tcx> ConstKind<'tcx> {
129 #[inline]
130 /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
131 /// unevaluated constant.
132 pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
923072b8 133 self.try_eval_for_typeck(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
3dfed10e
XL
134 }
135
136 #[inline]
137 /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
138 /// return `None`.
04454e1e 139 // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
923072b8 140 pub fn try_eval_for_mir(
3dfed10e
XL
141 self,
142 tcx: TyCtxt<'tcx>,
143 param_env: ParamEnv<'tcx>,
5e7ed085 144 ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
923072b8
FG
145 match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
146 Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
147 Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
148 Some(Err(e)) => Some(Err(e)),
149 None => None,
150 }
151 }
152
153 #[inline]
154 /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
155 /// return `None`.
156 // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
157 pub fn try_eval_for_typeck(
158 self,
159 tcx: TyCtxt<'tcx>,
160 param_env: ParamEnv<'tcx>,
161 ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
162 match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
163 Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
164 Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
165 Some(Err(e)) => Some(Err(e)),
166 None => None,
167 }
168 }
169
170 #[inline]
171 fn try_eval_inner(
172 self,
173 tcx: TyCtxt<'tcx>,
174 param_env: ParamEnv<'tcx>,
175 eval_mode: EvalMode,
176 ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
94222f64 177 if let ConstKind::Unevaluated(unevaluated) = self {
3dfed10e
XL
178 use crate::mir::interpret::ErrorHandled;
179
180 // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
181 // also does later, but we want to do it before checking for
182 // inference variables.
183 // Note that we erase regions *before* calling `with_reveal_all_normalized`,
184 // so that we don't try to invoke this query with
185 // any region variables.
94222f64 186 let param_env_and = tcx
fc512014 187 .erase_regions(param_env)
3dfed10e 188 .with_reveal_all_normalized(tcx)
94222f64 189 .and(tcx.erase_regions(unevaluated));
3dfed10e
XL
190
191 // HACK(eddyb) when the query key would contain inference variables,
192 // attempt using identity substs and `ParamEnv` instead, that will succeed
193 // when the expression doesn't depend on any parameters.
194 // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
195 // we can call `infcx.const_eval_resolve` which handles inference variables.
94222f64
XL
196 let param_env_and = if param_env_and.needs_infer() {
197 tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
198 def: unevaluated.def,
5099ac24 199 substs: InternalSubsts::identity_for_item(tcx, unevaluated.def.did),
94222f64
XL
200 promoted: unevaluated.promoted,
201 })
3dfed10e 202 } else {
94222f64 203 param_env_and
3dfed10e
XL
204 };
205
206 // FIXME(eddyb) maybe the `const_eval_*` methods should take
94222f64
XL
207 // `ty::ParamEnvAnd` instead of having them separate.
208 let (param_env, unevaluated) = param_env_and.into_parts();
3dfed10e
XL
209 // try to resolve e.g. associated constants to their definition on an impl, and then
210 // evaluate the const.
923072b8
FG
211 match eval_mode {
212 EvalMode::Typeck => {
213 match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
214 // NOTE(eddyb) `val` contains no lifetimes/types/consts,
215 // and we use the original type, so nothing from `substs`
216 // (which may be identity substs, see above),
217 // can leak through `val` into the const we return.
218 Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
219 Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
220 Err(ErrorHandled::Reported(e)) => Some(Err(e)),
221 }
222 }
223 EvalMode::Mir => {
224 match tcx.const_eval_resolve(param_env, unevaluated, None) {
225 // NOTE(eddyb) `val` contains no lifetimes/types/consts,
226 // and we use the original type, so nothing from `substs`
227 // (which may be identity substs, see above),
228 // can leak through `val` into the const we return.
229 Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
230 Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
231 Err(ErrorHandled::Reported(e)) => Some(Err(e)),
232 }
233 }
3dfed10e
XL
234 }
235 } else {
236 None
237 }
238 }
239}