]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/ty/consts.rs
New upstream version 1.75.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / ty / consts.rs
CommitLineData
9ffffee4 1use crate::middle::resolve_bound_vars as rbv;
781aab86 2use crate::mir::interpret::{AllocId, ErrorHandled, LitToConstInput, Scalar};
add651ee 3use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
5099ac24 4use rustc_data_structures::intern::Interned;
fe692bf9 5use rustc_error_messages::MultiSpan;
3dfed10e 6use rustc_hir as hir;
9ffffee4 7use rustc_hir::def::{DefKind, Res};
353b0b11 8use rustc_hir::def_id::LocalDefId;
3dfed10e
XL
9use rustc_macros::HashStable;
10
11mod int;
12mod kind;
6a06907d 13mod valtree;
3dfed10e
XL
14
15pub use int::*;
16pub use kind::*;
781aab86 17use rustc_span::Span;
fe692bf9 18use rustc_span::DUMMY_SP;
6a06907d 19pub use valtree::*;
3dfed10e 20
fe692bf9
FG
21use 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 26pub 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 30pub 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 36static_assert_size!(ConstData<'_>, 40);
3dfed10e
XL
37
38impl<'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
409pub 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}