1 use rustc_index::vec::Idx;
2 use rustc_middle::mir::*;
3 use rustc_middle::ty::{Ty, TyCtxt};
4 use rustc_target::abi::VariantIdx;
6 use std::convert::TryFrom;
7 use std::iter::TrustedLen;
9 /// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields.
11 /// Produces something like
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,
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),
36 lhs = tcx.mk_place_downcast(orig_lhs, adt_def, variant_index);
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 },
49 // Operands are upvars stored on the base place, so no
50 // downcast is necessary.
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();
62 ProjectionElem::ConstantIndex { offset, min_length: offset + 1, from_end: false },
65 let field = Field::new(active_field_index.unwrap_or(i));
66 tcx.mk_place_field(lhs, field, ty)
70 kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))),
73 [Statement { source_info, kind: StatementKind::Deinit(Box::new(orig_lhs)) }]
76 .chain(set_discriminant)