]>
Commit | Line | Data |
---|---|---|
923072b8 | 1 | use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; |
dfeec247 XL |
2 | |
3 | use crate::mir; | |
cdc7bbd5 | 4 | use crate::ty::subst::InternalSubsts; |
064997fb | 5 | use crate::ty::visit::TypeVisitable; |
923072b8 | 6 | use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt}; |
dfeec247 | 7 | use rustc_hir::def_id::DefId; |
923072b8 | 8 | use rustc_span::{Span, DUMMY_SP}; |
dfeec247 XL |
9 | |
10 | impl<'tcx> TyCtxt<'tcx> { | |
11 | /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts | |
12 | /// that can't take any generic arguments like statics, const items or enum discriminants. If a | |
13 | /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. | |
923072b8 | 14 | #[instrument(skip(self), level = "debug")] |
1b1a35ee | 15 | pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { |
dfeec247 XL |
16 | // In some situations def_id will have substitutions within scope, but they aren't allowed |
17 | // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions | |
74b04a01 | 18 | // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are |
dfeec247 XL |
19 | // encountered. |
20 | let substs = InternalSubsts::identity_for_item(self, def_id); | |
21 | let instance = ty::Instance::new(def_id, substs); | |
22 | let cid = GlobalId { instance, promoted: None }; | |
3dfed10e | 23 | let param_env = self.param_env(def_id).with_reveal_all_normalized(self); |
74b04a01 | 24 | self.const_eval_global_id(param_env, cid, None) |
dfeec247 | 25 | } |
dfeec247 XL |
26 | /// Resolves and evaluates a constant. |
27 | /// | |
28 | /// The constant can be located on a trait like `<A as B>::C`, in which case the given | |
29 | /// substitutions and environment are used to resolve the constant. Alternatively if the | |
30 | /// constant has generic parameters in scope the substitutions are used to evaluate the value of | |
31 | /// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count | |
32 | /// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still | |
33 | /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is | |
34 | /// returned. | |
6a06907d | 35 | #[instrument(level = "debug", skip(self))] |
dfeec247 XL |
36 | pub fn const_eval_resolve( |
37 | self, | |
38 | param_env: ty::ParamEnv<'tcx>, | |
cdc7bbd5 | 39 | ct: ty::Unevaluated<'tcx>, |
dfeec247 | 40 | span: Option<Span>, |
1b1a35ee | 41 | ) -> EvalToConstValueResult<'tcx> { |
5e7ed085 FG |
42 | // Cannot resolve `Unevaluated` constants that contain inference |
43 | // variables. We reject those here since `resolve_opt_const_arg` | |
44 | // would fail otherwise. | |
45 | // | |
46 | // When trying to evaluate constants containing inference variables, | |
47 | // use `Infcx::const_eval_resolve` instead. | |
48 | if ct.substs.has_infer_types_or_consts() { | |
49 | bug!("did not expect inference variables here"); | |
50 | } | |
51 | ||
5099ac24 | 52 | match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { |
f9f354fc | 53 | Ok(Some(instance)) => { |
cdc7bbd5 | 54 | let cid = GlobalId { instance, promoted: ct.promoted }; |
f9f354fc XL |
55 | self.const_eval_global_id(param_env, cid, span) |
56 | } | |
57 | Ok(None) => Err(ErrorHandled::TooGeneric), | |
58 | Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), | |
dfeec247 XL |
59 | } |
60 | } | |
61 | ||
923072b8 FG |
62 | #[instrument(level = "debug", skip(self))] |
63 | pub fn const_eval_resolve_for_typeck( | |
64 | self, | |
65 | param_env: ty::ParamEnv<'tcx>, | |
66 | ct: ty::Unevaluated<'tcx>, | |
67 | span: Option<Span>, | |
68 | ) -> EvalToValTreeResult<'tcx> { | |
69 | // Cannot resolve `Unevaluated` constants that contain inference | |
70 | // variables. We reject those here since `resolve_opt_const_arg` | |
71 | // would fail otherwise. | |
72 | // | |
73 | // When trying to evaluate constants containing inference variables, | |
74 | // use `Infcx::const_eval_resolve` instead. | |
75 | if ct.substs.has_infer_types_or_consts() { | |
76 | bug!("did not expect inference variables here"); | |
77 | } | |
78 | ||
79 | match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { | |
80 | Ok(Some(instance)) => { | |
81 | let cid = GlobalId { instance, promoted: ct.promoted }; | |
82 | self.const_eval_global_id_for_typeck(param_env, cid, span) | |
83 | } | |
84 | Ok(None) => Err(ErrorHandled::TooGeneric), | |
85 | Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), | |
86 | } | |
87 | } | |
88 | ||
dfeec247 XL |
89 | pub fn const_eval_instance( |
90 | self, | |
91 | param_env: ty::ParamEnv<'tcx>, | |
92 | instance: ty::Instance<'tcx>, | |
93 | span: Option<Span>, | |
1b1a35ee | 94 | ) -> EvalToConstValueResult<'tcx> { |
74b04a01 | 95 | self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span) |
dfeec247 XL |
96 | } |
97 | ||
923072b8 FG |
98 | /// Evaluate a constant to a `ConstValue`. |
99 | #[instrument(skip(self), level = "debug")] | |
74b04a01 | 100 | pub fn const_eval_global_id( |
dfeec247 XL |
101 | self, |
102 | param_env: ty::ParamEnv<'tcx>, | |
74b04a01 XL |
103 | cid: GlobalId<'tcx>, |
104 | span: Option<Span>, | |
1b1a35ee | 105 | ) -> EvalToConstValueResult<'tcx> { |
a2a8927a | 106 | let param_env = param_env.with_const(); |
74b04a01 XL |
107 | // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should |
108 | // improve caching of queries. | |
fc512014 | 109 | let inputs = self.erase_regions(param_env.and(cid)); |
74b04a01 | 110 | if let Some(span) = span { |
1b1a35ee | 111 | self.at(span).eval_to_const_value_raw(inputs) |
74b04a01 | 112 | } else { |
1b1a35ee | 113 | self.eval_to_const_value_raw(inputs) |
74b04a01 | 114 | } |
dfeec247 | 115 | } |
3dfed10e | 116 | |
923072b8 FG |
117 | /// Evaluate a constant to a type-level constant. |
118 | #[instrument(skip(self), level = "debug")] | |
119 | pub fn const_eval_global_id_for_typeck( | |
120 | self, | |
121 | param_env: ty::ParamEnv<'tcx>, | |
122 | cid: GlobalId<'tcx>, | |
123 | span: Option<Span>, | |
124 | ) -> EvalToValTreeResult<'tcx> { | |
125 | let param_env = param_env.with_const(); | |
126 | debug!(?param_env); | |
127 | // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should | |
128 | // improve caching of queries. | |
129 | let inputs = self.erase_regions(param_env.and(cid)); | |
130 | debug!(?inputs); | |
131 | if let Some(span) = span { | |
132 | self.at(span).eval_to_valtree(inputs) | |
133 | } else { | |
134 | self.eval_to_valtree(inputs) | |
135 | } | |
136 | } | |
137 | ||
138 | /// Evaluate a static's initializer, returning the allocation of the initializer's memory. | |
139 | #[inline(always)] | |
140 | pub fn eval_static_initializer( | |
141 | self, | |
142 | def_id: DefId, | |
143 | ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { | |
144 | self.at(DUMMY_SP).eval_static_initializer(def_id) | |
145 | } | |
146 | } | |
147 | ||
148 | impl<'tcx> TyCtxtAt<'tcx> { | |
3dfed10e XL |
149 | /// Evaluate a static's initializer, returning the allocation of the initializer's memory. |
150 | pub fn eval_static_initializer( | |
151 | self, | |
152 | def_id: DefId, | |
5e7ed085 | 153 | ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { |
3dfed10e XL |
154 | trace!("eval_static_initializer: Need to compute {:?}", def_id); |
155 | assert!(self.is_static(def_id)); | |
923072b8 | 156 | let instance = ty::Instance::mono(*self, def_id); |
3dfed10e XL |
157 | let gid = GlobalId { instance, promoted: None }; |
158 | self.eval_to_allocation(gid, ty::ParamEnv::reveal_all()) | |
159 | } | |
160 | ||
161 | /// Evaluate anything constant-like, returning the allocation of the final memory. | |
162 | fn eval_to_allocation( | |
163 | self, | |
164 | gid: GlobalId<'tcx>, | |
165 | param_env: ty::ParamEnv<'tcx>, | |
5e7ed085 | 166 | ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { |
a2a8927a | 167 | let param_env = param_env.with_const(); |
3dfed10e | 168 | trace!("eval_to_allocation: Need to compute {:?}", gid); |
1b1a35ee | 169 | let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; |
3dfed10e XL |
170 | Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) |
171 | } | |
923072b8 | 172 | } |
5099ac24 | 173 | |
923072b8 FG |
174 | impl<'tcx> TyCtxtEnsure<'tcx> { |
175 | /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts | |
176 | /// that can't take any generic arguments like statics, const items or enum discriminants. If a | |
177 | /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. | |
178 | #[instrument(skip(self), level = "debug")] | |
179 | pub fn const_eval_poly(self, def_id: DefId) { | |
180 | // In some situations def_id will have substitutions within scope, but they aren't allowed | |
181 | // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions | |
182 | // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are | |
183 | // encountered. | |
184 | let substs = InternalSubsts::identity_for_item(self.tcx, def_id); | |
185 | let instance = ty::Instance::new(def_id, substs); | |
186 | let cid = GlobalId { instance, promoted: None }; | |
187 | let param_env = | |
188 | self.tcx.param_env(def_id).with_reveal_all_normalized(self.tcx).with_const(); | |
189 | // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should | |
190 | // improve caching of queries. | |
191 | let inputs = self.tcx.erase_regions(param_env.and(cid)); | |
192 | self.eval_to_const_value_raw(inputs) | |
193 | } | |
194 | ||
195 | /// Evaluate a static's initializer, returning the allocation of the initializer's memory. | |
196 | pub fn eval_static_initializer(self, def_id: DefId) { | |
197 | trace!("eval_static_initializer: Need to compute {:?}", def_id); | |
198 | assert!(self.tcx.is_static(def_id)); | |
199 | let instance = ty::Instance::mono(self.tcx, def_id); | |
200 | let gid = GlobalId { instance, promoted: None }; | |
201 | let param_env = ty::ParamEnv::reveal_all().with_const(); | |
202 | trace!("eval_to_allocation: Need to compute {:?}", gid); | |
203 | self.eval_to_allocation_raw(param_env.and(gid)) | |
204 | } | |
205 | } | |
206 | ||
207 | impl<'tcx> TyCtxt<'tcx> { | |
923072b8 | 208 | /// Destructure a mir constant ADT or array into its variant index and its field values. |
064997fb | 209 | /// Panics if the destructuring fails, use `try_destructure_mir_constant` for fallible version. |
923072b8 | 210 | pub fn destructure_mir_constant( |
5099ac24 | 211 | self, |
923072b8 FG |
212 | param_env: ty::ParamEnv<'tcx>, |
213 | constant: mir::ConstantKind<'tcx>, | |
214 | ) -> mir::DestructuredMirConstant<'tcx> { | |
215 | self.try_destructure_mir_constant(param_env.and(constant)).unwrap() | |
5099ac24 | 216 | } |
dfeec247 | 217 | } |