]>
Commit | Line | Data |
---|---|---|
6a06907d XL |
1 | use std::convert::TryInto; |
2 | ||
136023e0 | 3 | use crate::mir::interpret::{AllocId, ConstValue, Scalar}; |
3dfed10e XL |
4 | use crate::mir::Promoted; |
5 | use crate::ty::subst::{InternalSubsts, SubstsRef}; | |
6 | use crate::ty::ParamEnv; | |
7 | use crate::ty::{self, TyCtxt, TypeFoldable}; | |
5e7ed085 | 8 | use rustc_errors::ErrorGuaranteed; |
3dfed10e XL |
9 | use rustc_hir::def_id::DefId; |
10 | use rustc_macros::HashStable; | |
11 | use rustc_target::abi::Size; | |
12 | ||
6a06907d | 13 | use 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 | 17 | pub 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 | ||
23 | impl<'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 | ||
31 | impl<'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 | ||
38 | impl<'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 |
48 | pub 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 |
74 | static_assert_size!(ConstKind<'_>, 40); |
75 | ||
76 | impl<'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)] | |
111 | pub 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 |
118 | enum EvalMode { |
119 | Typeck, | |
120 | Mir, | |
121 | } | |
122 | ||
123 | enum EvalResult<'tcx> { | |
124 | ValTree(ty::ValTree<'tcx>), | |
125 | ConstVal(ConstValue<'tcx>), | |
126 | } | |
127 | ||
3dfed10e XL |
128 | impl<'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 | } |