]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_const_eval/src/util/aggregate.rs
rename Unevaluated to UnevaluatedConst
[rust.git] / compiler / rustc_const_eval / src / util / aggregate.rs
1 use rustc_index::vec::Idx;
2 use rustc_middle::mir::*;
3 use rustc_middle::ty::{Ty, TyCtxt};
4 use rustc_target::abi::VariantIdx;
5
6 use std::convert::TryFrom;
7 use std::iter::TrustedLen;
8
9 /// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields.
10 ///
11 /// Produces something like
12 ///
13 /// (lhs as Variant).field0 = arg0;     // We only have a downcast if this is an enum
14 /// (lhs as Variant).field1 = arg1;
15 /// discriminant(lhs) = variant_index;  // If lhs is an enum or generator.
16 pub fn expand_aggregate<'tcx>(
17     orig_lhs: Place<'tcx>,
18     operands: impl Iterator<Item = (Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
19     kind: AggregateKind<'tcx>,
20     source_info: SourceInfo,
21     tcx: TyCtxt<'tcx>,
22 ) -> impl Iterator<Item = Statement<'tcx>> + TrustedLen {
23     let mut lhs = orig_lhs;
24     let mut set_discriminant = None;
25     let active_field_index = match kind {
26         AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => {
27             let adt_def = tcx.adt_def(adt_did);
28             if adt_def.is_enum() {
29                 set_discriminant = Some(Statement {
30                     kind: StatementKind::SetDiscriminant {
31                         place: Box::new(orig_lhs),
32                         variant_index,
33                     },
34                     source_info,
35                 });
36                 lhs = tcx.mk_place_downcast(orig_lhs, adt_def, variant_index);
37             }
38             active_field_index
39         }
40         AggregateKind::Generator(..) => {
41             // Right now we only support initializing generators to
42             // variant 0 (Unresumed).
43             let variant_index = VariantIdx::new(0);
44             set_discriminant = Some(Statement {
45                 kind: StatementKind::SetDiscriminant { place: Box::new(orig_lhs), variant_index },
46                 source_info,
47             });
48
49             // Operands are upvars stored on the base place, so no
50             // downcast is necessary.
51
52             None
53         }
54         _ => None,
55     };
56
57     let operands = operands.enumerate().map(move |(i, (op, ty))| {
58         let lhs_field = if let AggregateKind::Array(_) = kind {
59             let offset = u64::try_from(i).unwrap();
60             tcx.mk_place_elem(
61                 lhs,
62                 ProjectionElem::ConstantIndex { offset, min_length: offset + 1, from_end: false },
63             )
64         } else {
65             let field = Field::new(active_field_index.unwrap_or(i));
66             tcx.mk_place_field(lhs, field, ty)
67         };
68         Statement {
69             source_info,
70             kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))),
71         }
72     });
73     [Statement { source_info, kind: StatementKind::Deinit(Box::new(orig_lhs)) }]
74         .into_iter()
75         .chain(operands)
76         .chain(set_discriminant)
77 }