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