1use super::*;
3use rustc_const_eval::interpret::{InterpResult, interp_ok};
4use rustc_middle::mir::interpret;
5use rustc_middle::{mir, ty};
6
7impl ConstantLiteral {
8 fn byte_str(bytes: Vec<u8>) -> Self {
12 match String::from_utf8(bytes.clone()) {
13 Ok(s) => Self::Str(s),
14 Err(_) => Self::ByteStr(bytes),
15 }
16 }
17}
18
19#[tracing::instrument(level = "trace", skip(s))]
20pub(crate) fn scalar_int_to_constant_literal<'tcx, S: UnderOwnerState<'tcx>>(
21 s: &S,
22 x: rustc_middle::ty::ScalarInt,
23 ty: rustc_middle::ty::Ty<'tcx>,
24) -> ConstantLiteral {
25 match ty.kind() {
26 ty::Char => ConstantLiteral::Char(
27 char::try_from(x).s_expect(s, "scalar_int_to_constant_literal: expected a char"),
28 ),
29 ty::Bool => ConstantLiteral::Bool(
30 x.try_to_bool()
31 .s_expect(s, "scalar_int_to_constant_literal: expected a bool"),
32 ),
33 ty::Int(kind) => {
34 let v = x.to_int(x.size());
35 ConstantLiteral::Int(ConstantInt::Int(v, kind.sinto(s)))
36 }
37 ty::Uint(kind) => {
38 let v = x.to_uint(x.size());
39 ConstantLiteral::Int(ConstantInt::Uint(v, kind.sinto(s)))
40 }
41 ty::Float(kind) => {
42 let v = x.to_bits_unchecked();
43 bits_and_type_to_float_constant_literal(v, kind.sinto(s))
44 }
45 _ => {
46 let ty_sinto: Ty = ty.sinto(s);
47 supposely_unreachable_fatal!(
48 s,
49 "scalar_int_to_constant_literal_ExpectedLiteralType";
50 { ty, ty_sinto, x }
51 )
52 }
53 }
54}
55
56fn bits_and_type_to_float_constant_literal(bits: u128, ty: FloatTy) -> ConstantLiteral {
58 use rustc_apfloat::{Float, ieee};
59 let string = match &ty {
60 FloatTy::F16 => ieee::Half::from_bits(bits).to_string(),
61 FloatTy::F32 => ieee::Single::from_bits(bits).to_string(),
62 FloatTy::F64 => ieee::Double::from_bits(bits).to_string(),
63 FloatTy::F128 => ieee::Quad::from_bits(bits).to_string(),
64 };
65 ConstantLiteral::Float(string, ty)
66}
67
68impl ConstantExprKind {
69 pub fn decorate(self, ty: Ty, span: Span) -> Decorated<Self> {
70 Decorated {
71 contents: Box::new(self),
72 hir_id: None,
73 attributes: vec![],
74 ty,
75 span,
76 }
77 }
78}
79
80pub(crate) fn is_anon_const(
87 did: rustc_span::def_id::DefId,
88 tcx: rustc_middle::ty::TyCtxt<'_>,
89) -> bool {
90 matches!(
91 tcx.def_kind(did),
92 rustc_hir::def::DefKind::AnonConst | rustc_hir::def::DefKind::InlineConst
93 )
94}
95
96pub fn translate_constant_reference<'tcx>(
100 s: &impl UnderOwnerState<'tcx>,
101 span: rustc_span::Span,
102 ucv: rustc_middle::ty::UnevaluatedConst<'tcx>,
103) -> Option<ConstantExpr> {
104 let tcx = s.base().tcx;
105 if s.base().options.inline_anon_consts && is_anon_const(ucv.def, tcx) {
106 return None;
107 }
108 let typing_env = s.typing_env();
109 let ty = s.base().tcx.type_of(ucv.def).instantiate(tcx, ucv.args);
110 let ty = tcx
111 .try_normalize_erasing_regions(typing_env, ty)
112 .unwrap_or(ty);
113 let kind = if let Some(assoc) = s.base().tcx.opt_associated_item(ucv.def)
114 && matches!(
115 assoc.container,
116 ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(..)
117 ) {
118 let name = assoc.name().to_string();
120 let impl_expr = self_clause_for_item(s, ucv.def, ucv.args).unwrap();
121 ConstantExprKind::TraitConst { impl_expr, name }
122 } else {
123 let item = translate_item_ref(s, ucv.def, ucv.args);
124 ConstantExprKind::GlobalName(item)
125 };
126 let cv = kind.decorate(ty.sinto(s), span.sinto(s));
127 Some(cv)
128}
129
130pub fn eval_ty_constant<'tcx, S: UnderOwnerState<'tcx>>(
132 s: &S,
133 uv: rustc_middle::ty::UnevaluatedConst<'tcx>,
134) -> Option<ty::Const<'tcx>> {
135 use ty::TypeVisitableExt;
136 let tcx = s.base().tcx;
137 let typing_env = s.typing_env();
138 if uv.has_non_region_param() {
139 return None;
140 }
141 let span = tcx.def_span(uv.def);
142 let erased_uv = tcx.erase_and_anonymize_regions(uv);
143 let val = tcx
144 .const_eval_resolve_for_typeck(typing_env, erased_uv, span)
145 .ok()?
146 .ok()?;
147 let ty = tcx.type_of(uv.def).instantiate(tcx, uv.args);
148 Some(ty::Const::new_value(tcx, val, ty))
149}
150
151pub fn eval_mir_constant<'tcx, S: UnderOwnerState<'tcx>>(
153 s: &S,
154 c: mir::Const<'tcx>,
155) -> Option<mir::Const<'tcx>> {
156 let evaluated = c
157 .eval(s.base().tcx, s.typing_env(), rustc_span::DUMMY_SP)
158 .ok()?;
159 let evaluated = mir::Const::Val(evaluated, c.ty());
160 (evaluated != c).then_some(evaluated)
161}
162
163impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, ConstantExpr> for ty::Const<'tcx> {
164 #[tracing::instrument(level = "trace", skip(s))]
165 fn sinto(&self, s: &S) -> ConstantExpr {
166 use rustc_middle::query::Key;
167 let span = self.default_span(s.base().tcx);
168 match self.kind() {
169 ty::ConstKind::Param(p) => {
170 let ty = p.find_const_ty_from_env(s.param_env());
171 let kind = ConstantExprKind::ConstRef { id: p.sinto(s) };
172 kind.decorate(ty.sinto(s), span.sinto(s))
173 }
174 ty::ConstKind::Infer(..) => {
175 fatal!(s[span], "ty::ConstKind::Infer node? {:#?}", self)
176 }
177
178 ty::ConstKind::Unevaluated(ucv) => match translate_constant_reference(s, span, ucv) {
179 Some(val) => val,
180 None => match eval_ty_constant(s, ucv) {
181 Some(val) => val.sinto(s),
182 None => supposely_unreachable_fatal!(s, "TranslateUneval"; {self, ucv}),
184 },
185 },
186
187 ty::ConstKind::Value(val) => valtree_to_constant_expr(s, val.valtree, val.ty, span),
188 ty::ConstKind::Error(_) => fatal!(s[span], "ty::ConstKind::Error"),
189 ty::ConstKind::Expr(e) => fatal!(s[span], "ty::ConstKind::Expr {:#?}", e),
190
191 ty::ConstKind::Bound(i, bound) => {
192 supposely_unreachable_fatal!(s[span], "ty::ConstKind::Bound"; {i, bound})
193 }
194 _ => fatal!(s[span], "unexpected case"),
195 }
196 }
197}
198
199impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, ConstantExpr> for ty::Value<'tcx> {
200 #[tracing::instrument(level = "trace", skip(s))]
201 fn sinto(&self, s: &S) -> ConstantExpr {
202 valtree_to_constant_expr(s, self.valtree, self.ty, rustc_span::DUMMY_SP)
203 }
204}
205
206#[tracing::instrument(level = "trace", skip(s))]
207pub(crate) fn valtree_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>(
208 s: &S,
209 valtree: rustc_middle::ty::ValTree<'tcx>,
210 ty: rustc_middle::ty::Ty<'tcx>,
211 span: rustc_span::Span,
212) -> ConstantExpr {
213 let kind = match (&*valtree, ty.kind()) {
214 (_, ty::Ref(_, inner_ty, _)) => {
215 ConstantExprKind::Borrow(valtree_to_constant_expr(s, valtree, *inner_ty, span))
216 }
217 (ty::ValTreeKind::Branch(valtrees), ty::Str) => {
218 let bytes = valtrees
219 .iter()
220 .map(|x| match &***x {
221 ty::ValTreeKind::Leaf(leaf) => leaf.to_u8(),
222 _ => fatal!(
223 s[span],
224 "Expected a flat list of leaves while translating \
225 a str literal, got a arbitrary valtree."
226 ),
227 })
228 .collect();
229 ConstantExprKind::Literal(ConstantLiteral::byte_str(bytes))
230 }
231 (
232 ty::ValTreeKind::Branch(_),
233 ty::Array(..) | ty::Slice(..) | ty::Tuple(..) | ty::Adt(..),
234 ) => {
235 let tcx = s.base().tcx;
236 let contents: rustc_middle::ty::DestructuredConst =
237 tcx.destructure_const(ty::Const::new_value(s.base().tcx, valtree, ty));
238 let fields = contents.fields.iter().copied();
239 match ty.kind() {
240 ty::Slice(inner_ty) => {
241 let array_ty = {
242 let size = rustc_middle::ty::ScalarInt::try_from_target_usize(
243 fields.len() as u128,
244 tcx,
245 )
246 .s_unwrap(s);
247 let valtree = rustc_middle::ty::ValTree::from_scalar_int(tcx, size);
248 let value = rustc_middle::ty::Value {
249 ty: *inner_ty,
250 valtree,
251 };
252 let len = tcx.mk_ct_from_kind(rustc_middle::ty::ConstKind::Value(value));
253 tcx.mk_ty_from_kind(rustc_middle::ty::TyKind::Array(*inner_ty, len))
254 };
255 let array = ConstantExprKind::Array {
256 fields: fields.map(|field| field.sinto(s)).collect(),
257 }
258 .decorate(array_ty.sinto(s), span.sinto(s));
259 ConstantExprKind::Borrow(array)
260 }
261 ty::Array(_, _) => ConstantExprKind::Array {
262 fields: fields.map(|field| field.sinto(s)).collect(),
263 },
264 ty::Tuple(_) => ConstantExprKind::Tuple {
265 fields: fields.map(|field| field.sinto(s)).collect(),
266 },
267 ty::Adt(def, _) => {
268 let variant_idx = contents
269 .variant
270 .s_expect(s, "destructed const of adt without variant idx");
271 let variant_def = &def.variant(variant_idx);
272
273 ConstantExprKind::Adt {
274 info: get_variant_information(def, variant_idx, s),
275 fields: fields
276 .into_iter()
277 .zip(&variant_def.fields)
278 .map(|(value, field)| ConstantFieldExpr {
279 field: field.did.sinto(s),
280 value: value.sinto(s),
281 })
282 .collect(),
283 }
284 }
285 _ => unreachable!(),
286 }
287 }
288 (ty::ValTreeKind::Leaf(x), ty::RawPtr(_, _)) => {
289 use crate::rustc_type_ir::inherent::Ty;
290 let raw_address = x.to_bits_unchecked();
291 let uint_ty = UintTy::Usize;
292 let usize_ty = rustc_middle::ty::Ty::new_usize(s.base().tcx).sinto(s);
293 let lit = ConstantLiteral::Int(ConstantInt::Uint(raw_address, uint_ty));
294 ConstantExprKind::Cast {
295 source: ConstantExprKind::Literal(lit).decorate(usize_ty, span.sinto(s)),
296 }
297 }
298 (ty::ValTreeKind::Leaf(x), _) => {
299 ConstantExprKind::Literal(scalar_int_to_constant_literal(s, *x, ty))
300 }
301 _ => supposely_unreachable_fatal!(
302 s[span], "valtree_to_expr";
303 {valtree, ty}
304 ),
305 };
306 kind.decorate(ty.sinto(s), span.sinto(s))
307}
308
309fn op_to_const<'tcx, S: UnderOwnerState<'tcx>>(
312 s: &S,
313 span: rustc_span::Span,
314 ecx: &rustc_const_eval::const_eval::CompileTimeInterpCx<'tcx>,
315 op: rustc_const_eval::interpret::OpTy<'tcx>,
316) -> InterpResult<'tcx, ConstantExpr> {
317 use crate::rustc_const_eval::interpret::Projectable;
318 let tcx = s.base().tcx;
321 let ty = op.layout.ty;
322 let read_fields = |of: rustc_const_eval::interpret::OpTy<'tcx>, field_count| {
324 (0..field_count).map(move |i| {
325 let field_op = ecx.project_field(&of, rustc_abi::FieldIdx::from_usize(i))?;
326 op_to_const(s, span, &ecx, field_op)
327 })
328 };
329 let kind = match ty.kind() {
330 _ if let Some(place) = op.as_mplace_or_imm().left()
332 && let ptr = place.ptr()
333 && let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr, 0)?
334 && let interpret::GlobalAlloc::Static(did) = tcx.global_alloc(alloc_id) =>
335 {
336 let item = translate_item_ref(s, did, ty::GenericArgsRef::default());
337 ConstantExprKind::GlobalName(item)
338 }
339 ty::Char | ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Float(_) => {
340 let scalar = ecx.read_scalar(&op)?;
341 let scalar_int = scalar.try_to_scalar_int().unwrap();
342 let lit = scalar_int_to_constant_literal(s, scalar_int, ty);
343 ConstantExprKind::Literal(lit)
344 }
345 ty::Adt(adt_def, ..) if adt_def.is_union() => {
346 ConstantExprKind::Todo("Cannot translate constant of union type".into())
347 }
348 ty::Adt(adt_def, ..) => {
349 let variant = ecx.read_discriminant(&op)?;
350 let down = ecx.project_downcast(&op, variant)?;
351 let field_count = adt_def.variants()[variant].fields.len();
352 let fields = read_fields(down, field_count)
353 .zip(&adt_def.variant(variant).fields)
354 .map(|(value, field)| {
355 interp_ok(ConstantFieldExpr {
356 field: field.did.sinto(s),
357 value: value?,
358 })
359 })
360 .collect::<InterpResult<Vec<_>>>()?;
361 let variants_info = get_variant_information(adt_def, variant, s);
362 ConstantExprKind::Adt {
363 info: variants_info,
364 fields,
365 }
366 }
367 ty::Closure(def_id, args) => {
368 let def_id: DefId = def_id.sinto(s);
370 let field_count = args.as_closure().upvar_tys().len();
371 let fields = read_fields(op, field_count)
372 .map(|value| {
373 interp_ok(ConstantFieldExpr {
374 field: def_id.clone(),
377 value: value?,
378 })
379 })
380 .collect::<InterpResult<Vec<_>>>()?;
381 let variants_info = VariantInformations {
382 type_namespace: def_id.parent.clone().unwrap(),
383 typ: def_id.clone(),
384 variant: def_id,
385 kind: VariantKind::Struct { named: false },
386 };
387 ConstantExprKind::Adt {
388 info: variants_info,
389 fields,
390 }
391 }
392 ty::Tuple(args) => {
393 let fields = read_fields(op, args.len()).collect::<InterpResult<Vec<_>>>()?;
394 ConstantExprKind::Tuple { fields }
395 }
396 ty::Array(..) | ty::Slice(..) => {
397 let len = op.len(ecx)?;
398 let fields = (0..len)
399 .map(|i| {
400 let op = ecx.project_index(&op, i)?;
401 op_to_const(s, span, ecx, op)
402 })
403 .collect::<InterpResult<Vec<_>>>()?;
404 ConstantExprKind::Array { fields }
405 }
406 ty::Str => {
407 let str = ecx.read_str(&op.assert_mem_place())?;
408 ConstantExprKind::Literal(ConstantLiteral::Str(str.to_owned()))
409 }
410 ty::FnDef(def_id, args) => {
411 let item = translate_item_ref(s, *def_id, args);
412 ConstantExprKind::FnPtr(item)
413 }
414 ty::RawPtr(..) | ty::Ref(..) => {
415 if let Some(op) = ecx.deref_pointer(&op).discard_err() {
416 let val = op_to_const(s, span, ecx, op.into())?;
418 match ty.kind() {
419 ty::Ref(..) => ConstantExprKind::Borrow(val),
420 ty::RawPtr(.., mutability) => ConstantExprKind::RawBorrow {
421 arg: val,
422 mutability: mutability.sinto(s),
423 },
424 _ => unreachable!(),
425 }
426 } else {
427 let scalar = ecx.read_scalar(&op)?;
429 let scalar_int = scalar.try_to_scalar_int().unwrap();
430 let v = scalar_int.to_uint(scalar_int.size());
431 let lit = ConstantLiteral::PtrNoProvenance(v);
432 ConstantExprKind::Literal(lit)
433 }
434 }
435 ty::FnPtr(..)
436 | ty::Dynamic(..)
437 | ty::Foreign(..)
438 | ty::Pat(..)
439 | ty::UnsafeBinder(..)
440 | ty::CoroutineClosure(..)
441 | ty::Coroutine(..)
442 | ty::CoroutineWitness(..) => ConstantExprKind::Todo("Unhandled constant type".into()),
443 ty::Alias(..) | ty::Param(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
444 fatal!(s[span], "Encountered evaluated constant of non-monomorphic type"; {op})
445 }
446 ty::Never | ty::Error(..) => {
447 fatal!(s[span], "Encountered evaluated constant of invalid type"; {ty})
448 }
449 };
450 let val = kind.decorate(ty.sinto(s), span.sinto(s));
451 interp_ok(val)
452}
453
454pub fn const_value_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>(
455 s: &S,
456 ty: rustc_middle::ty::Ty<'tcx>,
457 val: mir::ConstValue,
458 span: rustc_span::Span,
459) -> InterpResult<'tcx, ConstantExpr> {
460 let tcx = s.base().tcx;
461 let typing_env = s.typing_env();
462 let (ecx, op) =
463 rustc_const_eval::const_eval::mk_eval_cx_for_const_val(tcx.at(span), typing_env, val, ty)
464 .unwrap();
465 op_to_const(s, span, &ecx, op)
466}