]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_middle/src/ty/consts/kind.rs
Update upstream source from tag 'upstream/1.50.0+dfsg1'
[rustc.git] / compiler / rustc_middle / src / ty / consts / kind.rs
1 use crate::mir::interpret::ConstValue;
2 use crate::mir::interpret::Scalar;
3 use crate::mir::Promoted;
4 use crate::ty::subst::{InternalSubsts, SubstsRef};
5 use crate::ty::ParamEnv;
6 use crate::ty::{self, TyCtxt, TypeFoldable};
7 use rustc_errors::ErrorReported;
8 use rustc_hir::def_id::DefId;
9 use rustc_macros::HashStable;
10 use rustc_target::abi::Size;
11
12 /// Represents a constant in Rust.
13 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
14 #[derive(HashStable)]
15 pub enum ConstKind<'tcx> {
16 /// A const generic parameter.
17 Param(ty::ParamConst),
18
19 /// Infer the value of the const.
20 Infer(InferConst<'tcx>),
21
22 /// Bound const variable, used only when preparing a trait query.
23 Bound(ty::DebruijnIndex, ty::BoundVar),
24
25 /// A placeholder const - universally quantified higher-ranked const.
26 Placeholder(ty::PlaceholderConst<'tcx>),
27
28 /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
29 /// variants when the code is monomorphic enough for that.
30 Unevaluated(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>, Option<Promoted>),
31
32 /// Used to hold computed value.
33 Value(ConstValue<'tcx>),
34
35 /// A placeholder for a const which could not be computed; this is
36 /// propagated to avoid useless error messages.
37 Error(ty::DelaySpanBugEmitted),
38 }
39
40 #[cfg(target_arch = "x86_64")]
41 static_assert_size!(ConstKind<'_>, 40);
42
43 impl<'tcx> ConstKind<'tcx> {
44 #[inline]
45 pub fn try_to_value(self) -> Option<ConstValue<'tcx>> {
46 if let ConstKind::Value(val) = self { Some(val) } else { None }
47 }
48
49 #[inline]
50 pub fn try_to_scalar(self) -> Option<Scalar> {
51 self.try_to_value()?.try_to_scalar()
52 }
53
54 #[inline]
55 pub fn try_to_bits(self, size: Size) -> Option<u128> {
56 self.try_to_value()?.try_to_bits(size)
57 }
58
59 #[inline]
60 pub fn try_to_bool(self) -> Option<bool> {
61 self.try_to_value()?.try_to_bool()
62 }
63
64 #[inline]
65 pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
66 self.try_to_value()?.try_to_machine_usize(tcx)
67 }
68 }
69
70 /// An inference variable for a const, for use in const generics.
71 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
72 #[derive(HashStable)]
73 pub enum InferConst<'tcx> {
74 /// Infer the value of the const.
75 Var(ty::ConstVid<'tcx>),
76 /// A fresh const variable. See `infer::freshen` for more details.
77 Fresh(u32),
78 }
79
80 impl<'tcx> ConstKind<'tcx> {
81 #[inline]
82 /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
83 /// unevaluated constant.
84 pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
85 self.try_eval(tcx, param_env).and_then(Result::ok).map(ConstKind::Value).unwrap_or(self)
86 }
87
88 #[inline]
89 /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
90 /// return `None`.
91 pub(super) fn try_eval(
92 self,
93 tcx: TyCtxt<'tcx>,
94 param_env: ParamEnv<'tcx>,
95 ) -> Option<Result<ConstValue<'tcx>, ErrorReported>> {
96 if let ConstKind::Unevaluated(def, substs, promoted) = self {
97 use crate::mir::interpret::ErrorHandled;
98
99 // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
100 // also does later, but we want to do it before checking for
101 // inference variables.
102 // Note that we erase regions *before* calling `with_reveal_all_normalized`,
103 // so that we don't try to invoke this query with
104 // any region variables.
105 let param_env_and_substs = tcx
106 .erase_regions(param_env)
107 .with_reveal_all_normalized(tcx)
108 .and(tcx.erase_regions(substs));
109
110 // HACK(eddyb) when the query key would contain inference variables,
111 // attempt using identity substs and `ParamEnv` instead, that will succeed
112 // when the expression doesn't depend on any parameters.
113 // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
114 // we can call `infcx.const_eval_resolve` which handles inference variables.
115 let param_env_and_substs = if param_env_and_substs.needs_infer() {
116 tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did))
117 } else {
118 param_env_and_substs
119 };
120
121 // FIXME(eddyb) maybe the `const_eval_*` methods should take
122 // `ty::ParamEnvAnd<SubstsRef>` instead of having them separate.
123 let (param_env, substs) = param_env_and_substs.into_parts();
124 // try to resolve e.g. associated constants to their definition on an impl, and then
125 // evaluate the const.
126 match tcx.const_eval_resolve(param_env, def, substs, promoted, None) {
127 // NOTE(eddyb) `val` contains no lifetimes/types/consts,
128 // and we use the original type, so nothing from `substs`
129 // (which may be identity substs, see above),
130 // can leak through `val` into the const we return.
131 Ok(val) => Some(Ok(val)),
132 Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
133 Err(ErrorHandled::Reported(e)) => Some(Err(e)),
134 }
135 } else {
136 None
137 }
138 }
139 }