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>(
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 set_discriminant = None;
24 let active_field_index = match kind {
25 AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
26 if adt_def.is_enum() {
27 set_discriminant = Some(Statement {
28 kind: StatementKind::SetDiscriminant { place: box (lhs), variant_index },
31 lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index);
35 AggregateKind::Generator(..) => {
36 // Right now we only support initializing generators to
37 // variant 0 (Unresumed).
38 let variant_index = VariantIdx::new(0);
39 set_discriminant = Some(Statement {
40 kind: StatementKind::SetDiscriminant { place: box (lhs), variant_index },
44 // Operands are upvars stored on the base place, so no
45 // downcast is necessary.
54 .map(move |(i, (op, ty))| {
55 let lhs_field = if let AggregateKind::Array(_) = kind {
56 let offset = u64::try_from(i).unwrap();
59 ProjectionElem::ConstantIndex {
61 min_length: offset + 1,
66 let field = Field::new(active_field_index.unwrap_or(i));
67 tcx.mk_place_field(lhs, field, ty)
69 Statement { source_info, kind: StatementKind::Assign(box (lhs_field, Rvalue::Use(op))) }
71 .chain(set_discriminant)