1 use rustc_middle::ty::{self, TyCtxt};
2 use rustc_target::abi::VariantIdx;
6 /// Destructures array, ADT or tuple constants into the constants
8 pub(crate) fn destructure_const<'tcx>(
10 const_: ty::Const<'tcx>,
11 ) -> ty::DestructuredConst<'tcx> {
12 let ty::ConstKind::Value(valtree) = const_.kind() else {
13 bug!("cannot destructure constant {:?}", const_)
16 let branches = match valtree {
17 ty::ValTree::Branch(b) => b,
18 _ => bug!("cannot destructure constant {:?}", const_),
21 let (fields, variant) = match const_.ty().kind() {
22 ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
23 // construct the consts for the elements of the array/slice
24 let field_consts = branches
26 .map(|b| tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty }))
28 debug!(?field_consts);
32 ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"),
33 ty::Adt(def, substs) => {
34 let (variant_idx, branches) = if def.is_enum() {
35 let (head, rest) = branches.split_first().unwrap();
36 (VariantIdx::from_u32(head.unwrap_leaf().try_to_u32().unwrap()), rest)
38 (VariantIdx::from_u32(0), branches)
40 let fields = &def.variant(variant_idx).fields;
41 let mut field_consts = Vec::with_capacity(fields.len());
43 for (field, field_valtree) in iter::zip(fields, branches) {
44 let field_ty = field.ty(tcx, substs);
45 let field_const = tcx.mk_const(ty::ConstS {
46 kind: ty::ConstKind::Value(*field_valtree),
49 field_consts.push(field_const);
51 debug!(?field_consts);
53 (field_consts, Some(variant_idx))
55 ty::Tuple(elem_tys) => {
56 let fields = iter::zip(*elem_tys, branches)
57 .map(|(elem_ty, elem_valtree)| {
58 tcx.mk_const(ty::ConstS {
59 kind: ty::ConstKind::Value(*elem_valtree),
67 _ => bug!("cannot destructure constant {:?}", const_),
70 let fields = tcx.arena.alloc_from_iter(fields.into_iter());
72 ty::DestructuredConst { variant, fields }
75 pub fn provide(providers: &mut ty::query::Providers) {
76 *providers = ty::query::Providers { destructure_const, ..*providers };