]>
Commit | Line | Data |
---|---|---|
9ffffee4 | 1 | use crate::middle::resolve_bound_vars as rbv; |
781aab86 | 2 | use crate::mir::interpret::{AllocId, ErrorHandled, LitToConstInput, Scalar}; |
add651ee | 3 | use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; |
5099ac24 | 4 | use rustc_data_structures::intern::Interned; |
fe692bf9 | 5 | use rustc_error_messages::MultiSpan; |
3dfed10e | 6 | use rustc_hir as hir; |
9ffffee4 | 7 | use rustc_hir::def::{DefKind, Res}; |
353b0b11 | 8 | use rustc_hir::def_id::LocalDefId; |
3dfed10e XL |
9 | use rustc_macros::HashStable; |
10 | ||
11 | mod int; | |
12 | mod kind; | |
6a06907d | 13 | mod valtree; |
3dfed10e XL |
14 | |
15 | pub use int::*; | |
16 | pub use kind::*; | |
781aab86 | 17 | use rustc_span::Span; |
fe692bf9 | 18 | use rustc_span::DUMMY_SP; |
6a06907d | 19 | pub use valtree::*; |
3dfed10e | 20 | |
fe692bf9 FG |
21 | use super::sty::ConstKind; |
22 | ||
9ffffee4 | 23 | /// Use this rather than `ConstData`, whenever possible. |
5099ac24 | 24 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] |
5e7ed085 | 25 | #[rustc_pass_by_value] |
9c376795 | 26 | pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>); |
5099ac24 | 27 | |
3dfed10e | 28 | /// Typed constant value. |
5099ac24 | 29 | #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)] |
9c376795 | 30 | pub struct ConstData<'tcx> { |
3dfed10e | 31 | pub ty: Ty<'tcx>, |
923072b8 | 32 | pub kind: ConstKind<'tcx>, |
f035d41b XL |
33 | } |
34 | ||
6a06907d | 35 | #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] |
9c376795 | 36 | static_assert_size!(ConstData<'_>, 40); |
3dfed10e XL |
37 | |
38 | impl<'tcx> Const<'tcx> { | |
04454e1e | 39 | #[inline] |
5099ac24 FG |
40 | pub fn ty(self) -> Ty<'tcx> { |
41 | self.0.ty | |
42 | } | |
43 | ||
04454e1e | 44 | #[inline] |
923072b8 | 45 | pub fn kind(self) -> ConstKind<'tcx> { |
fe692bf9 FG |
46 | self.0.kind.clone() |
47 | } | |
48 | ||
49 | #[inline] | |
50 | pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { | |
51 | tcx.mk_ct_from_kind(kind, ty) | |
52 | } | |
53 | ||
54 | #[inline] | |
55 | pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst, ty: Ty<'tcx>) -> Const<'tcx> { | |
56 | Const::new(tcx, ty::ConstKind::Param(param), ty) | |
57 | } | |
58 | ||
59 | #[inline] | |
ed00b5ec | 60 | pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid, ty: Ty<'tcx>) -> Const<'tcx> { |
fe692bf9 FG |
61 | Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty) |
62 | } | |
63 | ||
64 | #[inline] | |
65 | pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32, ty: Ty<'tcx>) -> Const<'tcx> { | |
66 | Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)), ty) | |
67 | } | |
68 | ||
69 | #[inline] | |
ed00b5ec | 70 | pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Const<'tcx> { |
fe692bf9 FG |
71 | Const::new(tcx, ty::ConstKind::Infer(infer), ty) |
72 | } | |
73 | ||
74 | #[inline] | |
75 | pub fn new_bound( | |
76 | tcx: TyCtxt<'tcx>, | |
77 | debruijn: ty::DebruijnIndex, | |
78 | var: ty::BoundVar, | |
79 | ty: Ty<'tcx>, | |
80 | ) -> Const<'tcx> { | |
81 | Const::new(tcx, ty::ConstKind::Bound(debruijn, var), ty) | |
82 | } | |
83 | ||
84 | #[inline] | |
85 | pub fn new_placeholder( | |
86 | tcx: TyCtxt<'tcx>, | |
ed00b5ec | 87 | placeholder: ty::PlaceholderConst, |
fe692bf9 FG |
88 | ty: Ty<'tcx>, |
89 | ) -> Const<'tcx> { | |
90 | Const::new(tcx, ty::ConstKind::Placeholder(placeholder), ty) | |
91 | } | |
92 | ||
93 | #[inline] | |
94 | pub fn new_unevaluated( | |
95 | tcx: TyCtxt<'tcx>, | |
96 | uv: ty::UnevaluatedConst<'tcx>, | |
97 | ty: Ty<'tcx>, | |
98 | ) -> Const<'tcx> { | |
99 | Const::new(tcx, ty::ConstKind::Unevaluated(uv), ty) | |
100 | } | |
101 | ||
102 | #[inline] | |
103 | pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { | |
104 | Const::new(tcx, ty::ConstKind::Value(val), ty) | |
105 | } | |
106 | ||
107 | #[inline] | |
108 | pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { | |
109 | Const::new(tcx, ty::ConstKind::Expr(expr), ty) | |
110 | } | |
111 | ||
112 | #[inline] | |
113 | pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed, ty: Ty<'tcx>) -> Const<'tcx> { | |
114 | Const::new(tcx, ty::ConstKind::Error(e), ty) | |
115 | } | |
116 | ||
117 | /// Like [Ty::new_error] but for constants. | |
118 | #[track_caller] | |
119 | pub fn new_misc_error(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { | |
120 | Const::new_error_with_message( | |
121 | tcx, | |
122 | ty, | |
123 | DUMMY_SP, | |
124 | "ty::ConstKind::Error constructed but no error reported", | |
125 | ) | |
126 | } | |
127 | ||
128 | /// Like [Ty::new_error_with_message] but for constants. | |
129 | #[track_caller] | |
130 | pub fn new_error_with_message<S: Into<MultiSpan>>( | |
131 | tcx: TyCtxt<'tcx>, | |
132 | ty: Ty<'tcx>, | |
133 | span: S, | |
134 | msg: &'static str, | |
135 | ) -> Const<'tcx> { | |
136 | let reported = tcx.sess.delay_span_bug(span, msg); | |
137 | Const::new_error(tcx, reported, ty) | |
5099ac24 FG |
138 | } |
139 | ||
3dfed10e XL |
140 | /// Literals and const generic parameters are eagerly converted to a constant, everything else |
141 | /// becomes `Unevaluated`. | |
5099ac24 | 142 | #[instrument(skip(tcx), level = "debug")] |
49aad941 FG |
143 | pub fn from_anon_const(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self { |
144 | let body_id = match tcx.hir().get_by_def_id(def) { | |
3dfed10e XL |
145 | hir::Node::AnonConst(ac) => ac.body, |
146 | _ => span_bug!( | |
49aad941 | 147 | tcx.def_span(def.to_def_id()), |
3dfed10e XL |
148 | "from_anon_const can only process anonymous constants" |
149 | ), | |
150 | }; | |
151 | ||
152 | let expr = &tcx.hir().body(body_id).value; | |
5099ac24 | 153 | debug!(?expr); |
3dfed10e | 154 | |
49aad941 | 155 | let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic"); |
3dfed10e | 156 | |
781aab86 | 157 | match Self::try_from_lit_or_param(tcx, ty, expr) { |
3c0e092e | 158 | Some(v) => v, |
fe692bf9 FG |
159 | None => ty::Const::new_unevaluated( |
160 | tcx, | |
487cf647 | 161 | ty::UnevaluatedConst { |
49aad941 | 162 | def: def.to_def_id(), |
add651ee | 163 | args: GenericArgs::identity_for_item(tcx, def.to_def_id()), |
487cf647 | 164 | }, |
3c0e092e | 165 | ty, |
487cf647 | 166 | ), |
3c0e092e XL |
167 | } |
168 | } | |
169 | ||
5099ac24 | 170 | #[instrument(skip(tcx), level = "debug")] |
781aab86 | 171 | fn try_from_lit_or_param( |
3c0e092e XL |
172 | tcx: TyCtxt<'tcx>, |
173 | ty: Ty<'tcx>, | |
174 | expr: &'tcx hir::Expr<'tcx>, | |
5099ac24 FG |
175 | ) -> Option<Self> { |
176 | // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments | |
177 | // currently have to be wrapped in curly brackets, so it's necessary to special-case. | |
178 | let expr = match &expr.kind { | |
179 | hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { | |
180 | block.expr.as_ref().unwrap() | |
181 | } | |
182 | _ => expr, | |
183 | }; | |
184 | ||
3dfed10e XL |
185 | let lit_input = match expr.kind { |
186 | hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), | |
6a06907d | 187 | hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { |
3dfed10e XL |
188 | hir::ExprKind::Lit(ref lit) => { |
189 | Some(LitToConstInput { lit: &lit.node, ty, neg: true }) | |
f035d41b | 190 | } |
3dfed10e XL |
191 | _ => None, |
192 | }, | |
193 | _ => None, | |
194 | }; | |
195 | ||
196 | if let Some(lit_input) = lit_input { | |
197 | // If an error occurred, ignore that it's a literal and leave reporting the error up to | |
198 | // mir. | |
5099ac24 FG |
199 | match tcx.at(expr.span).lit_to_const(lit_input) { |
200 | Ok(c) => return Some(c), | |
201 | Err(e) => { | |
202 | tcx.sess.delay_span_bug( | |
203 | expr.span, | |
add651ee | 204 | format!("Const::from_anon_const: couldn't lit_to_const {e:?}"), |
5099ac24 FG |
205 | ); |
206 | } | |
f035d41b | 207 | } |
3dfed10e XL |
208 | } |
209 | ||
3c0e092e | 210 | match expr.kind { |
9ffffee4 FG |
211 | hir::ExprKind::Path(hir::QPath::Resolved( |
212 | _, | |
213 | &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }, | |
214 | )) => { | |
353b0b11 FG |
215 | // Use the type from the param's definition, since we can resolve it, |
216 | // not the expected parameter type from WithOptConstParam. | |
add651ee | 217 | let param_ty = tcx.type_of(def_id).instantiate_identity(); |
9ffffee4 FG |
218 | match tcx.named_bound_var(expr.hir_id) { |
219 | Some(rbv::ResolvedArg::EarlyBound(_)) => { | |
220 | // Find the name and index of the const parameter by indexing the generics of | |
221 | // the parent item and construct a `ParamConst`. | |
222 | let item_def_id = tcx.parent(def_id); | |
223 | let generics = tcx.generics_of(item_def_id); | |
224 | let index = generics.param_def_id_to_index[&def_id]; | |
225 | let name = tcx.item_name(def_id); | |
fe692bf9 FG |
226 | Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty)) |
227 | } | |
228 | Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { | |
229 | Some(ty::Const::new_bound( | |
230 | tcx, | |
231 | debruijn, | |
232 | ty::BoundVar::from_u32(index), | |
233 | param_ty, | |
234 | )) | |
235 | } | |
236 | Some(rbv::ResolvedArg::Error(guar)) => { | |
237 | Some(ty::Const::new_error(tcx, guar, param_ty)) | |
9ffffee4 | 238 | } |
9ffffee4 FG |
239 | arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), |
240 | } | |
f035d41b | 241 | } |
3c0e092e XL |
242 | _ => None, |
243 | } | |
244 | } | |
245 | ||
3dfed10e XL |
246 | #[inline] |
247 | /// Creates a constant with the given integer value and interns it. | |
5099ac24 | 248 | pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self { |
3dfed10e XL |
249 | let size = tcx |
250 | .layout_of(ty) | |
add651ee | 251 | .unwrap_or_else(|e| panic!("could not compute layout for {ty:?}: {e:?}")) |
3dfed10e | 252 | .size; |
fe692bf9 FG |
253 | ty::Const::new_value( |
254 | tcx, | |
487cf647 FG |
255 | ty::ValTree::from_scalar_int(ScalarInt::try_from_uint(bits, size).unwrap()), |
256 | ty.value, | |
257 | ) | |
3dfed10e XL |
258 | } |
259 | ||
260 | #[inline] | |
261 | /// Creates an interned zst constant. | |
5099ac24 | 262 | pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { |
fe692bf9 | 263 | ty::Const::new_value(tcx, ty::ValTree::zst(), ty) |
3dfed10e XL |
264 | } |
265 | ||
266 | #[inline] | |
267 | /// Creates an interned bool constant. | |
5099ac24 | 268 | pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self { |
3dfed10e XL |
269 | Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool)) |
270 | } | |
271 | ||
272 | #[inline] | |
273 | /// Creates an interned usize constant. | |
9ffffee4 | 274 | pub fn from_target_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self { |
3dfed10e XL |
275 | Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) |
276 | } | |
277 | ||
781aab86 FG |
278 | /// Returns the evaluated constant |
279 | #[inline] | |
280 | pub fn eval( | |
281 | self, | |
282 | tcx: TyCtxt<'tcx>, | |
283 | param_env: ParamEnv<'tcx>, | |
284 | span: Option<Span>, | |
285 | ) -> Result<ValTree<'tcx>, ErrorHandled> { | |
286 | assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); | |
add651ee | 287 | match self.kind() { |
781aab86 FG |
288 | ConstKind::Unevaluated(unevaluated) => { |
289 | // FIXME(eddyb) maybe the `const_eval_*` methods should take | |
290 | // `ty::ParamEnvAnd` instead of having them separate. | |
291 | let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env); | |
292 | // try to resolve e.g. associated constants to their definition on an impl, and then | |
293 | // evaluate the const. | |
294 | let c = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?; | |
295 | Ok(c.expect("`ty::Const::eval` called on a non-valtree-compatible type")) | |
296 | } | |
297 | ConstKind::Value(val) => Ok(val), | |
298 | ConstKind::Error(g) => Err(g.into()), | |
299 | ConstKind::Param(_) | |
300 | | ConstKind::Infer(_) | |
301 | | ConstKind::Bound(_, _) | |
302 | | ConstKind::Placeholder(_) | |
303 | | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))), | |
add651ee FG |
304 | } |
305 | } | |
306 | ||
781aab86 FG |
307 | /// Normalizes the constant to a value or an error if possible. |
308 | #[inline] | |
309 | pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { | |
310 | match self.eval(tcx, param_env, None) { | |
311 | Ok(val) => Self::new_value(tcx, val, self.ty()), | |
312 | Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()), | |
313 | Err(ErrorHandled::TooGeneric(_span)) => self, | |
314 | } | |
315 | } | |
316 | ||
317 | #[inline] | |
318 | pub fn try_eval_scalar( | |
319 | self, | |
320 | tcx: TyCtxt<'tcx>, | |
321 | param_env: ty::ParamEnv<'tcx>, | |
322 | ) -> Option<Scalar> { | |
323 | self.eval(tcx, param_env, None).ok()?.try_to_scalar() | |
324 | } | |
325 | ||
3dfed10e XL |
326 | #[inline] |
327 | /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of | |
328 | /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it | |
329 | /// contains const generic parameters or pointers). | |
781aab86 | 330 | pub fn try_eval_scalar_int( |
5099ac24 | 331 | self, |
3dfed10e XL |
332 | tcx: TyCtxt<'tcx>, |
333 | param_env: ParamEnv<'tcx>, | |
781aab86 FG |
334 | ) -> Option<ScalarInt> { |
335 | self.try_eval_scalar(tcx, param_env)?.try_to_int().ok() | |
336 | } | |
337 | ||
338 | #[inline] | |
339 | /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of | |
340 | /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it | |
341 | /// contains const generic parameters or pointers). | |
342 | pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> { | |
343 | let int = self.try_eval_scalar_int(tcx, param_env)?; | |
344 | let size = | |
345 | tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size; | |
3dfed10e | 346 | // if `ty` does not depend on generic parameters, use an empty param_env |
781aab86 | 347 | int.to_bits(size).ok() |
3dfed10e XL |
348 | } |
349 | ||
350 | #[inline] | |
781aab86 FG |
351 | /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. |
352 | pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 { | |
353 | self.try_eval_bits(tcx, param_env) | |
354 | .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self)) | |
3dfed10e XL |
355 | } |
356 | ||
357 | #[inline] | |
9ffffee4 FG |
358 | pub fn try_eval_target_usize( |
359 | self, | |
360 | tcx: TyCtxt<'tcx>, | |
361 | param_env: ParamEnv<'tcx>, | |
362 | ) -> Option<u64> { | |
781aab86 | 363 | self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok() |
f035d41b | 364 | } |
3dfed10e XL |
365 | |
366 | #[inline] | |
781aab86 FG |
367 | pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { |
368 | self.try_eval_scalar_int(tcx, param_env)?.try_into().ok() | |
3dfed10e XL |
369 | } |
370 | ||
371 | #[inline] | |
372 | /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`. | |
9ffffee4 FG |
373 | pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 { |
374 | self.try_eval_target_usize(tcx, param_env) | |
3dfed10e XL |
375 | .unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) |
376 | } | |
2b03887a | 377 | |
781aab86 FG |
378 | /// Panics if self.kind != ty::ConstKind::Value |
379 | pub fn to_valtree(self) -> ty::ValTree<'tcx> { | |
380 | match self.kind() { | |
381 | ty::ConstKind::Value(valtree) => valtree, | |
382 | _ => bug!("expected ConstKind::Value, got {:?}", self.kind()), | |
fe692bf9 FG |
383 | } |
384 | } | |
385 | ||
781aab86 FG |
386 | /// Attempts to convert to a `ValTree` |
387 | pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> { | |
388 | match self.kind() { | |
389 | ty::ConstKind::Value(valtree) => Some(valtree), | |
390 | _ => None, | |
fe692bf9 FG |
391 | } |
392 | } | |
393 | ||
fe692bf9 FG |
394 | #[inline] |
395 | pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { | |
781aab86 | 396 | self.try_to_valtree()?.try_to_scalar() |
fe692bf9 FG |
397 | } |
398 | ||
399 | #[inline] | |
400 | pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { | |
781aab86 | 401 | self.try_to_valtree()?.try_to_target_usize(tcx) |
fe692bf9 FG |
402 | } |
403 | ||
2b03887a FG |
404 | pub fn is_ct_infer(self) -> bool { |
405 | matches!(self.kind(), ty::ConstKind::Infer(_)) | |
406 | } | |
f035d41b | 407 | } |
cdc7bbd5 | 408 | |
353b0b11 FG |
409 | pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Const<'_>> { |
410 | let default_def_id = match tcx.hir().get_by_def_id(def_id) { | |
cdc7bbd5 | 411 | hir::Node::GenericParam(hir::GenericParam { |
487cf647 | 412 | kind: hir::GenericParamKind::Const { default: Some(ac), .. }, |
cdc7bbd5 | 413 | .. |
487cf647 | 414 | }) => ac.def_id, |
cdc7bbd5 XL |
415 | _ => span_bug!( |
416 | tcx.def_span(def_id), | |
417 | "`const_param_default` expected a generic parameter with a constant" | |
418 | ), | |
419 | }; | |
fe692bf9 | 420 | ty::EarlyBinder::bind(Const::from_anon_const(tcx, default_def_id)) |
cdc7bbd5 | 421 | } |