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