1use super::*;
3use rustc_const_eval::interpret::{FnVal, 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 ty::Pat(inner, _) => scalar_int_to_constant_literal(s, x, *inner),
46 _ => {
47 let ty_sinto: Ty = ty.sinto(s);
48 supposely_unreachable_fatal!(
49 s,
50 "scalar_int_to_constant_literal_ExpectedLiteralType";
51 { ty, ty_sinto, x }
52 )
53 }
54 }
55}
56
57fn bits_and_type_to_float_constant_literal(bits: u128, ty: FloatTy) -> ConstantLiteral {
59 use rustc_apfloat::{Float, ieee};
60 let string = match &ty {
61 FloatTy::F16 => ieee::Half::from_bits(bits).to_string(),
62 FloatTy::F32 => ieee::Single::from_bits(bits).to_string(),
63 FloatTy::F64 => ieee::Double::from_bits(bits).to_string(),
64 FloatTy::F128 => ieee::Quad::from_bits(bits).to_string(),
65 };
66 ConstantLiteral::Float(string, ty)
67}
68
69impl ConstantExprKind {
70 pub fn decorate(self, ty: Ty, _span: Span) -> Decorated<Self> {
71 Decorated {
72 contents: Box::new(self),
73 ty,
74 }
75 }
76}
77
78pub(crate) fn is_anon_const(
85 did: rustc_span::def_id::DefId,
86 tcx: rustc_middle::ty::TyCtxt<'_>,
87) -> bool {
88 matches!(tcx.def_kind(did), rustc_hir::def::DefKind::AnonConst)
89}
90
91pub fn eval_ty_constant<'tcx, S: UnderOwnerState<'tcx>>(
93 s: &S,
94 uv: rustc_middle::ty::AliasConst<'tcx>,
95) -> Option<ty::Const<'tcx>> {
96 use ty::TypeVisitableExt;
97 let tcx = s.base().tcx;
98 let typing_env = s.typing_env();
99 if uv.has_non_region_param() {
100 return None;
101 }
102 let def = uv.kind.opt_def_id().unwrap();
103 let span = tcx.def_span(def);
104 let erased_uv = tcx.erase_and_anonymize_regions(uv);
105 let val = tcx
106 .const_eval_resolve_for_typeck(typing_env, erased_uv, span)
107 .ok()?
108 .ok()?;
109 let ty = tcx.type_of(def).instantiate(tcx, uv.args);
110 let ty = normalize(tcx, typing_env, ty);
111 Some(ty::Const::new_value(tcx, val, ty))
112}
113
114impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, ConstantExpr> for ty::Const<'tcx> {
115 #[tracing::instrument(level = "trace", skip(s))]
116 fn sinto(&self, s: &S) -> ConstantExpr {
117 let tcx = s.base().tcx;
118 let span = rustc_span::DUMMY_SP;
119 match self.kind() {
120 ty::ConstKind::Param(p) => {
121 let ty = p.find_const_ty_from_env(s.param_env());
122 let kind = ConstantExprKind::ConstRef { id: p.sinto(s) };
123 kind.decorate(ty.sinto(s), span.sinto(s))
124 }
125 ty::ConstKind::Infer(..) => {
126 fatal!(s[span], "ty::ConstKind::Infer node? {:#?}", self)
127 }
128
129 ty::ConstKind::Alias(_, ucv) => {
130 let def = ucv
131 .kind
132 .opt_def_id()
133 .expect("AliasConstKind with no def id?");
134 if s.base().options.inline_anon_consts
135 && is_anon_const(def, tcx)
136 && let Some(val) = eval_ty_constant(s, ucv)
137 {
138 val.sinto(s)
139 } else {
140 use rustc_middle::query::QueryKey;
141 let span = tcx
142 .def_ident_span(def)
143 .unwrap_or_else(|| def.default_span(tcx));
144 let item = translate_item_ref(s, def, ucv.args);
145 let kind = ConstantExprKind::NamedGlobal(item);
146 let ty = tcx.type_of(def).instantiate(tcx, ucv.args);
147 let ty = normalize(tcx, s.typing_env(), ty);
148 kind.decorate(ty.sinto(s), span.sinto(s))
149 }
150 }
151
152 ty::ConstKind::Value(val) => valtree_to_constant_expr(s, val.valtree, val.ty, span),
153 ty::ConstKind::Error(_) => fatal!(s[span], "ty::ConstKind::Error"),
154 ty::ConstKind::Expr(e) => fatal!(s[span], "ty::ConstKind::Expr {:#?}", e),
155
156 ty::ConstKind::Bound(i, bound) => {
157 supposely_unreachable_fatal!(s[span], "ty::ConstKind::Bound"; {i, bound})
158 }
159 _ => fatal!(s[span], "unexpected case"),
160 }
161 }
162}
163
164impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, ConstantExpr> for ty::Value<'tcx> {
165 #[tracing::instrument(level = "trace", skip(s))]
166 fn sinto(&self, s: &S) -> ConstantExpr {
167 valtree_to_constant_expr(s, self.valtree, self.ty, rustc_span::DUMMY_SP)
168 }
169}
170
171#[tracing::instrument(level = "trace", skip(s))]
172pub(crate) fn valtree_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>(
173 s: &S,
174 valtree: rustc_middle::ty::ValTree<'tcx>,
175 ty: rustc_middle::ty::Ty<'tcx>,
176 span: rustc_span::Span,
177) -> ConstantExpr {
178 let ty = normalize(s.base().tcx, s.typing_env(), ty::Unnormalized::new_wip(ty));
179
180 let kind = match (&*valtree, ty.kind()) {
181 (_, ty::Ref(_, inner_ty, _)) => {
182 ConstantExprKind::Borrow(valtree_to_constant_expr(s, valtree, *inner_ty, span))
183 }
184 (ty::ValTreeKind::Branch(valtrees), ty::Str) => {
185 let bytes = valtrees
186 .iter()
187 .map(|x| match x.try_to_leaf() {
188 Some(leaf) => leaf.to_u8(),
189 None => fatal!(
190 s[span],
191 "Expected a flat list of leaves while translating \
192 a str literal, got a arbitrary valtree."
193 ),
194 })
195 .collect();
196 ConstantExprKind::Literal(ConstantLiteral::byte_str(bytes))
197 }
198 (ty::ValTreeKind::Branch(fields), ty::Array(..) | ty::Slice(..) | ty::Tuple(..)) => {
199 let fields = fields.iter().map(|field| field.sinto(s)).collect();
200 match ty.kind() {
201 ty::Array(..) | ty::Slice(..) => ConstantExprKind::Array { fields },
202 ty::Tuple(_) => ConstantExprKind::Tuple { fields },
203 _ => unreachable!(),
204 }
205 }
206 (ty::ValTreeKind::Branch(_), ty::Adt(def, _)) => {
207 let contents: rustc_middle::ty::DestructuredAdtConst =
208 ty::Value { valtree, ty }.destructure_adt_const();
209
210 let fields = contents.fields.iter().copied();
211 let variant_idx = contents.variant;
212 let variant_def = &def.variant(variant_idx);
213
214 ConstantExprKind::Adt {
215 kind: get_variant_kind(def, variant_idx, s),
216 fields: fields
217 .into_iter()
218 .zip(&variant_def.fields)
219 .map(|(value, field)| ConstantFieldExpr {
220 field: field.did.sinto(s),
221 value: value.sinto(s),
222 })
223 .collect(),
224 }
225 }
226 (ty::ValTreeKind::Leaf(x), ty::RawPtr(_, _)) => {
227 let raw_address = x.to_bits_unchecked();
228 ConstantExprKind::Literal(ConstantLiteral::PtrNoProvenance(raw_address))
229 }
230 (ty::ValTreeKind::Leaf(x), _) => {
231 ConstantExprKind::Literal(scalar_int_to_constant_literal(s, *x, ty))
232 }
233 _ => supposely_unreachable_fatal!(
234 s[span], "valtree_to_expr";
235 {valtree, ty}
236 ),
237 };
238 kind.decorate(ty.sinto(s), span.sinto(s))
239}
240
241fn op_to_const<'tcx, S: UnderOwnerState<'tcx>>(
244 s: &S,
245 span: rustc_span::Span,
246 ecx: &rustc_const_eval::const_eval::CompileTimeInterpCx<'tcx>,
247 op: rustc_const_eval::interpret::OpTy<'tcx>,
248) -> InterpResult<'tcx, ConstantExpr> {
249 use rustc_const_eval::interpret::Projectable;
250 let tcx = s.base().tcx;
253 let ty = op.layout.ty;
254 let read_fields = |of: rustc_const_eval::interpret::OpTy<'tcx>, field_count| {
256 (0..field_count).map(move |i| {
257 let field_op = ecx.project_field(&of, rustc_abi::FieldIdx::from_usize(i))?;
258 op_to_const(s, span, ecx, field_op)
259 })
260 };
261 let kind = match ty.kind() {
262 _ if let Some(place) = op.as_mplace_or_imm().left()
264 && let ptr = place.ptr()
265 && let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr, 0)?
266 && let interpret::GlobalAlloc::Static(did) = tcx.global_alloc(alloc_id) =>
267 {
268 let item = translate_item_ref(s, did, ty::GenericArgsRef::default());
269 ConstantExprKind::NamedGlobal(item)
270 }
271 ty::Char | ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Float(_) => {
272 let scalar = ecx.read_scalar(&op)?;
273 let scalar_int = scalar.try_to_scalar_int().unwrap();
274 let lit = scalar_int_to_constant_literal(s, scalar_int, ty);
275 ConstantExprKind::Literal(lit)
276 }
277 ty::Adt(adt_def, ..) if adt_def.is_union() => {
278 ConstantExprKind::Todo("Cannot translate constant of union type".into())
279 }
280 ty::Adt(adt_def, ..) => {
281 let variant = ecx.read_discriminant(&op)?;
282 let op = if adt_def.is_enum() {
283 ecx.project_downcast(&op, variant)?
284 } else {
285 op
286 };
287 let field_count = adt_def.variants()[variant].fields.len();
288 let fields = read_fields(op, field_count)
289 .zip(&adt_def.variant(variant).fields)
290 .map(|(value, field)| {
291 interp_ok(ConstantFieldExpr {
292 field: field.did.sinto(s),
293 value: value?,
294 })
295 })
296 .collect::<InterpResult<Vec<_>>>()?;
297 ConstantExprKind::Adt {
298 kind: get_variant_kind(adt_def, variant, s),
299 fields,
300 }
301 }
302 ty::Closure(def_id, args) => {
303 let def_id: DefId = def_id.sinto(s);
305 let field_count = args.as_closure().upvar_tys().len();
306 let fields = read_fields(op, field_count)
307 .map(|value| {
308 interp_ok(ConstantFieldExpr {
309 field: def_id.clone(),
312 value: value?,
313 })
314 })
315 .collect::<InterpResult<Vec<_>>>()?;
316 ConstantExprKind::Adt {
317 kind: VariantKind::Struct,
318 fields,
319 }
320 }
321 ty::Tuple(args) => {
322 let fields = read_fields(op, args.len()).collect::<InterpResult<Vec<_>>>()?;
323 ConstantExprKind::Tuple { fields }
324 }
325 ty::Array(..) | ty::Slice(..) => {
326 let len = op.len(ecx)?;
327 let fields = (0..len)
328 .map(|i| {
329 let op = ecx.project_index(&op, i)?;
330 op_to_const(s, span, ecx, op)
331 })
332 .collect::<InterpResult<Vec<_>>>()?;
333 ConstantExprKind::Array { fields }
334 }
335 ty::Str => {
336 let str = ecx.read_str(&op.assert_mem_place())?;
337 ConstantExprKind::Literal(ConstantLiteral::Str(str.to_owned()))
338 }
339 ty::FnDef(def_id, args) => {
340 let args = args.no_bound_vars().expect("bound variables in FnDef");
341 let item = translate_item_ref(s, *def_id, args);
342 ConstantExprKind::FnDef(item)
343 }
344 ty::FnPtr(..) => {
345 let fn_ptr = ecx.read_pointer(&op)?;
346 let FnVal::Instance(instance) = ecx.get_ptr_fn(fn_ptr)?;
347 let def_id = instance.def_id();
348 let generics = instance.args;
349 let fun = translate_item_ref(s, def_id, generics);
350 ConstantExprKind::FnPtr(fun)
351 }
352 ty::RawPtr(..) | ty::Ref(..) => {
353 if let Some(op) = ecx.deref_pointer(&op).discard_err() {
354 let val = op_to_const(s, span, ecx, op.into())?;
356 match ty.kind() {
357 ty::Ref(..) => ConstantExprKind::Borrow(val),
358 ty::RawPtr(.., mutability) => ConstantExprKind::RawBorrow {
359 arg: val,
360 mutability: mutability.sinto(s),
361 },
362 _ => unreachable!(),
363 }
364 } else {
365 let scalar = ecx.read_scalar(&op)?;
367 let scalar_int = scalar.try_to_scalar_int().unwrap();
368 let v = scalar_int.to_uint(scalar_int.size());
369 let lit = ConstantLiteral::PtrNoProvenance(v);
370 ConstantExprKind::Literal(lit)
371 }
372 }
373 ty::Pat(..) => {
374 let op = ecx.project_field(&op, FieldIdx::from_u16(0))?;
375 *op_to_const(s, span, ecx, op)?.contents
376 }
377 ty::Dynamic(..)
378 | ty::Foreign(..)
379 | ty::UnsafeBinder(..)
380 | ty::CoroutineClosure(..)
381 | ty::Coroutine(..)
382 | ty::CoroutineWitness(..) => ConstantExprKind::Todo("Unhandled constant type".into()),
383 ty::Alias(..) | ty::Param(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
384 fatal!(s[span], "Encountered evaluated constant of non-monomorphic type"; {op})
385 }
386 ty::Never | ty::Error(..) => {
387 fatal!(s[span], "Encountered evaluated constant of invalid type"; {ty})
388 }
389 };
390 let val = kind.decorate(ty.sinto(s), span.sinto(s));
391 interp_ok(val)
392}
393
394pub fn const_value_to_constant_expr<'tcx, S: UnderOwnerState<'tcx>>(
395 s: &S,
396 ty: rustc_middle::ty::Ty<'tcx>,
397 val: mir::ConstValue,
398 span: rustc_span::Span,
399) -> InterpResult<'tcx, ConstantExpr> {
400 let tcx = s.base().tcx;
401 let typing_env = s.typing_env();
402 let (ecx, op) =
403 rustc_const_eval::const_eval::mk_eval_cx_for_const_val(tcx.at(span), typing_env, val, ty)
404 .unwrap();
405 op_to_const(s, span, &ecx, op)
406}