]>
Commit | Line | Data |
---|---|---|
6a06907d | 1 | use std::convert::TryInto; |
94222f64 | 2 | use std::fmt; |
6a06907d | 3 | |
136023e0 | 4 | use crate::mir::interpret::{AllocId, ConstValue, Scalar}; |
3dfed10e XL |
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; | |
13 | ||
6a06907d | 14 | use super::ScalarInt; |
cdc7bbd5 | 15 | /// An unevaluated, potentially generic, constant. |
94222f64 XL |
16 | /// |
17 | /// If `substs_` is `None` it means that this anon const | |
18 | /// still has its default substs. | |
19 | /// | |
20 | /// We check for all possible substs in `fn default_anon_const_substs`, | |
21 | /// so refer to that check for more info. | |
22 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] | |
cdc7bbd5 | 23 | #[derive(Hash, HashStable)] |
94222f64 | 24 | pub struct Unevaluated<'tcx, P = Option<Promoted>> { |
cdc7bbd5 | 25 | pub def: ty::WithOptConstParam<DefId>, |
94222f64 XL |
26 | pub substs_: Option<SubstsRef<'tcx>>, |
27 | pub promoted: P, | |
28 | } | |
29 | ||
30 | impl<'tcx> Unevaluated<'tcx> { | |
31 | #[inline] | |
32 | pub fn shrink(self) -> Unevaluated<'tcx, ()> { | |
33 | debug_assert_eq!(self.promoted, None); | |
34 | Unevaluated { def: self.def, substs_: self.substs_, promoted: () } | |
35 | } | |
36 | } | |
37 | ||
38 | impl<'tcx> Unevaluated<'tcx, ()> { | |
39 | #[inline] | |
40 | pub fn expand(self) -> Unevaluated<'tcx> { | |
41 | Unevaluated { def: self.def, substs_: self.substs_, promoted: None } | |
42 | } | |
43 | } | |
44 | ||
45 | impl<'tcx, P: Default> Unevaluated<'tcx, P> { | |
46 | #[inline] | |
47 | pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> { | |
48 | Unevaluated { def, substs_: Some(substs), promoted: Default::default() } | |
49 | } | |
50 | } | |
51 | ||
52 | impl<'tcx, P: Default + PartialEq + fmt::Debug> Unevaluated<'tcx, P> { | |
53 | #[inline] | |
54 | pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> { | |
55 | self.substs_.unwrap_or_else(|| { | |
56 | // We must not use the parents default substs for promoted constants | |
57 | // as that can result in incorrect substs and calls the `default_anon_const_substs` | |
58 | // for something that might not actually be a constant. | |
59 | debug_assert_eq!(self.promoted, Default::default()); | |
60 | tcx.default_anon_const_substs(self.def.did) | |
61 | }) | |
62 | } | |
cdc7bbd5 | 63 | } |
6a06907d | 64 | |
3dfed10e | 65 | /// Represents a constant in Rust. |
cdc7bbd5 XL |
66 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] |
67 | #[derive(Hash, HashStable)] | |
3dfed10e XL |
68 | pub enum ConstKind<'tcx> { |
69 | /// A const generic parameter. | |
70 | Param(ty::ParamConst), | |
71 | ||
72 | /// Infer the value of the const. | |
73 | Infer(InferConst<'tcx>), | |
74 | ||
75 | /// Bound const variable, used only when preparing a trait query. | |
76 | Bound(ty::DebruijnIndex, ty::BoundVar), | |
77 | ||
78 | /// A placeholder const - universally quantified higher-ranked const. | |
fc512014 | 79 | Placeholder(ty::PlaceholderConst<'tcx>), |
3dfed10e XL |
80 | |
81 | /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other | |
82 | /// variants when the code is monomorphic enough for that. | |
cdc7bbd5 | 83 | Unevaluated(Unevaluated<'tcx>), |
3dfed10e XL |
84 | |
85 | /// Used to hold computed value. | |
86 | Value(ConstValue<'tcx>), | |
87 | ||
88 | /// A placeholder for a const which could not be computed; this is | |
89 | /// propagated to avoid useless error messages. | |
90 | Error(ty::DelaySpanBugEmitted), | |
91 | } | |
92 | ||
6a06907d | 93 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
3dfed10e XL |
94 | static_assert_size!(ConstKind<'_>, 40); |
95 | ||
96 | impl<'tcx> ConstKind<'tcx> { | |
97 | #[inline] | |
98 | pub fn try_to_value(self) -> Option<ConstValue<'tcx>> { | |
99 | if let ConstKind::Value(val) = self { Some(val) } else { None } | |
100 | } | |
101 | ||
102 | #[inline] | |
136023e0 | 103 | pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { |
3dfed10e XL |
104 | self.try_to_value()?.try_to_scalar() |
105 | } | |
106 | ||
6a06907d XL |
107 | #[inline] |
108 | pub fn try_to_scalar_int(self) -> Option<ScalarInt> { | |
109 | Some(self.try_to_value()?.try_to_scalar()?.assert_int()) | |
110 | } | |
111 | ||
3dfed10e XL |
112 | #[inline] |
113 | pub fn try_to_bits(self, size: Size) -> Option<u128> { | |
6a06907d | 114 | self.try_to_scalar_int()?.to_bits(size).ok() |
3dfed10e XL |
115 | } |
116 | ||
117 | #[inline] | |
118 | pub fn try_to_bool(self) -> Option<bool> { | |
6a06907d | 119 | self.try_to_scalar_int()?.try_into().ok() |
3dfed10e XL |
120 | } |
121 | ||
122 | #[inline] | |
123 | pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { | |
124 | self.try_to_value()?.try_to_machine_usize(tcx) | |
125 | } | |
126 | } | |
127 | ||
128 | /// An inference variable for a const, for use in const generics. | |
129 | #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] | |
130 | #[derive(HashStable)] | |
131 | pub enum InferConst<'tcx> { | |
132 | /// Infer the value of the const. | |
133 | Var(ty::ConstVid<'tcx>), | |
134 | /// A fresh const variable. See `infer::freshen` for more details. | |
135 | Fresh(u32), | |
136 | } | |
137 | ||
138 | impl<'tcx> ConstKind<'tcx> { | |
139 | #[inline] | |
140 | /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the | |
141 | /// unevaluated constant. | |
142 | pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { | |
5869c6ff | 143 | self.try_eval(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value) |
3dfed10e XL |
144 | } |
145 | ||
146 | #[inline] | |
147 | /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary | |
148 | /// return `None`. | |
149 | pub(super) fn try_eval( | |
150 | self, | |
151 | tcx: TyCtxt<'tcx>, | |
152 | param_env: ParamEnv<'tcx>, | |
153 | ) -> Option<Result<ConstValue<'tcx>, ErrorReported>> { | |
94222f64 | 154 | if let ConstKind::Unevaluated(unevaluated) = self { |
3dfed10e XL |
155 | use crate::mir::interpret::ErrorHandled; |
156 | ||
157 | // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` | |
158 | // also does later, but we want to do it before checking for | |
159 | // inference variables. | |
160 | // Note that we erase regions *before* calling `with_reveal_all_normalized`, | |
161 | // so that we don't try to invoke this query with | |
162 | // any region variables. | |
94222f64 | 163 | let param_env_and = tcx |
fc512014 | 164 | .erase_regions(param_env) |
3dfed10e | 165 | .with_reveal_all_normalized(tcx) |
94222f64 | 166 | .and(tcx.erase_regions(unevaluated)); |
3dfed10e XL |
167 | |
168 | // HACK(eddyb) when the query key would contain inference variables, | |
169 | // attempt using identity substs and `ParamEnv` instead, that will succeed | |
170 | // when the expression doesn't depend on any parameters. | |
171 | // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that | |
172 | // we can call `infcx.const_eval_resolve` which handles inference variables. | |
94222f64 XL |
173 | let param_env_and = if param_env_and.needs_infer() { |
174 | tcx.param_env(unevaluated.def.did).and(ty::Unevaluated { | |
175 | def: unevaluated.def, | |
176 | substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)), | |
177 | promoted: unevaluated.promoted, | |
178 | }) | |
3dfed10e | 179 | } else { |
94222f64 | 180 | param_env_and |
3dfed10e XL |
181 | }; |
182 | ||
183 | // FIXME(eddyb) maybe the `const_eval_*` methods should take | |
94222f64 XL |
184 | // `ty::ParamEnvAnd` instead of having them separate. |
185 | let (param_env, unevaluated) = param_env_and.into_parts(); | |
3dfed10e XL |
186 | // try to resolve e.g. associated constants to their definition on an impl, and then |
187 | // evaluate the const. | |
94222f64 | 188 | match tcx.const_eval_resolve(param_env, unevaluated, None) { |
3dfed10e XL |
189 | // NOTE(eddyb) `val` contains no lifetimes/types/consts, |
190 | // and we use the original type, so nothing from `substs` | |
191 | // (which may be identity substs, see above), | |
192 | // can leak through `val` into the const we return. | |
193 | Ok(val) => Some(Ok(val)), | |
194 | Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None, | |
195 | Err(ErrorHandled::Reported(e)) => Some(Err(e)), | |
196 | } | |
197 | } else { | |
198 | None | |
199 | } | |
200 | } | |
201 | } |