]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/ty/consts/kind.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / consts / kind.rs
CommitLineData
6a06907d 1use std::convert::TryInto;
94222f64 2use std::fmt;
6a06907d 3
136023e0 4use crate::mir::interpret::{AllocId, ConstValue, Scalar};
3dfed10e
XL
5use crate::mir::Promoted;
6use crate::ty::subst::{InternalSubsts, SubstsRef};
7use crate::ty::ParamEnv;
8use crate::ty::{self, TyCtxt, TypeFoldable};
9use rustc_errors::ErrorReported;
10use rustc_hir::def_id::DefId;
11use rustc_macros::HashStable;
12use rustc_target::abi::Size;
13
6a06907d 14use 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 24pub 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
30impl<'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
38impl<'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
45impl<'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
52impl<'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
68pub 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
94static_assert_size!(ConstKind<'_>, 40);
95
96impl<'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)]
131pub 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
138impl<'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}