]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/mir/interpret/queries.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / mir / interpret / queries.rs
CommitLineData
923072b8 1use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
dfeec247
XL
2
3use crate::mir;
cdc7bbd5 4use crate::ty::subst::InternalSubsts;
064997fb 5use crate::ty::visit::TypeVisitable;
923072b8 6use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
dfeec247 7use rustc_hir::def_id::DefId;
923072b8 8use rustc_span::{Span, DUMMY_SP};
dfeec247
XL
9
10impl<'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
148impl<'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
174impl<'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
207impl<'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}