]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! See docs in build/expr/mod.rs | |
12 | ||
13 | use rustc_data_structures::fnv::FnvHashMap; | |
14 | ||
92a42be0 | 15 | use build::{BlockAnd, BlockAndExtension, Builder}; |
e9174d1e SL |
16 | use build::expr::category::{Category, RvalueFunc}; |
17 | use hair::*; | |
92a42be0 | 18 | use rustc::mir::repr::*; |
e9174d1e | 19 | |
b039eaaf | 20 | impl<'a,'tcx> Builder<'a,'tcx> { |
e9174d1e | 21 | /// Compile `expr`, yielding an rvalue. |
b039eaaf SL |
22 | pub fn as_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>> |
23 | where M: Mirror<'tcx, Output = Expr<'tcx>> | |
e9174d1e SL |
24 | { |
25 | let expr = self.hir.mirror(expr); | |
26 | self.expr_as_rvalue(block, expr) | |
27 | } | |
28 | ||
29 | fn expr_as_rvalue(&mut self, | |
30 | mut block: BasicBlock, | |
b039eaaf SL |
31 | expr: Expr<'tcx>) |
32 | -> BlockAnd<Rvalue<'tcx>> { | |
33 | debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr); | |
e9174d1e SL |
34 | |
35 | let this = self; | |
54a0048b | 36 | let scope_id = this.innermost_scope_id(); |
e9174d1e SL |
37 | let expr_span = expr.span; |
38 | ||
39 | match expr.kind { | |
40 | ExprKind::Scope { extent, value } => { | |
54a0048b | 41 | this.in_scope(extent, block, |this, _| this.as_rvalue(block, value)) |
e9174d1e | 42 | } |
54a0048b SL |
43 | ExprKind::InlineAsm { asm, outputs, inputs } => { |
44 | let outputs = outputs.into_iter().map(|output| { | |
45 | unpack!(block = this.as_lvalue(block, output)) | |
46 | }).collect(); | |
47 | ||
48 | let inputs = inputs.into_iter().map(|input| { | |
49 | unpack!(block = this.as_operand(block, input)) | |
50 | }).collect(); | |
51 | ||
52 | block.and(Rvalue::InlineAsm { | |
53 | asm: asm.clone(), | |
54 | outputs: outputs, | |
55 | inputs: inputs | |
56 | }) | |
e9174d1e SL |
57 | } |
58 | ExprKind::Repeat { value, count } => { | |
59 | let value_operand = unpack!(block = this.as_operand(block, value)); | |
92a42be0 | 60 | block.and(Rvalue::Repeat(value_operand, count)) |
e9174d1e SL |
61 | } |
62 | ExprKind::Borrow { region, borrow_kind, arg } => { | |
63 | let arg_lvalue = unpack!(block = this.as_lvalue(block, arg)); | |
64 | block.and(Rvalue::Ref(region, borrow_kind, arg_lvalue)) | |
65 | } | |
66 | ExprKind::Binary { op, lhs, rhs } => { | |
67 | let lhs = unpack!(block = this.as_operand(block, lhs)); | |
68 | let rhs = unpack!(block = this.as_operand(block, rhs)); | |
69 | block.and(Rvalue::BinaryOp(op, lhs, rhs)) | |
70 | } | |
71 | ExprKind::Unary { op, arg } => { | |
72 | let arg = unpack!(block = this.as_operand(block, arg)); | |
73 | block.and(Rvalue::UnaryOp(op, arg)) | |
74 | } | |
7453a54e | 75 | ExprKind::Box { value, value_extents } => { |
e9174d1e | 76 | let value = this.hir.mirror(value); |
7453a54e | 77 | let result = this.temp(expr.ty); |
e9174d1e | 78 | // to start, malloc some memory of suitable type (thus far, uninitialized): |
54a0048b SL |
79 | this.cfg.push_assign(block, scope_id, expr_span, &result, Rvalue::Box(value.ty)); |
80 | this.in_scope(value_extents, block, |this, _| { | |
7453a54e SL |
81 | // schedule a shallow free of that memory, lest we unwind: |
82 | this.schedule_box_free(expr_span, value_extents, &result, value.ty); | |
83 | // initialize the box contents: | |
84 | unpack!(block = this.into(&result.clone().deref(), block, value)); | |
85 | block.and(Rvalue::Use(Operand::Consume(result))) | |
86 | }) | |
e9174d1e SL |
87 | } |
88 | ExprKind::Cast { source } => { | |
54a0048b SL |
89 | let source = this.hir.mirror(source); |
90 | if source.ty == expr.ty { | |
91 | this.expr_as_rvalue(block, source) | |
92 | } else { | |
93 | let source = unpack!(block = this.as_operand(block, source)); | |
94 | block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) | |
95 | } | |
e9174d1e SL |
96 | } |
97 | ExprKind::ReifyFnPointer { source } => { | |
98 | let source = unpack!(block = this.as_operand(block, source)); | |
99 | block.and(Rvalue::Cast(CastKind::ReifyFnPointer, source, expr.ty)) | |
100 | } | |
101 | ExprKind::UnsafeFnPointer { source } => { | |
102 | let source = unpack!(block = this.as_operand(block, source)); | |
103 | block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty)) | |
104 | } | |
105 | ExprKind::Unsize { source } => { | |
106 | let source = unpack!(block = this.as_operand(block, source)); | |
107 | block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty)) | |
108 | } | |
109 | ExprKind::Vec { fields } => { | |
110 | // (*) We would (maybe) be closer to trans if we | |
111 | // handled this and other aggregate cases via | |
112 | // `into()`, not `as_rvalue` -- in that case, instead | |
113 | // of generating | |
114 | // | |
115 | // let tmp1 = ...1; | |
116 | // let tmp2 = ...2; | |
117 | // dest = Rvalue::Aggregate(Foo, [tmp1, tmp2]) | |
118 | // | |
119 | // we could just generate | |
120 | // | |
121 | // dest.f = ...1; | |
122 | // dest.g = ...2; | |
123 | // | |
124 | // The problem is that then we would need to: | |
125 | // | |
126 | // (a) have a more complex mechanism for handling | |
127 | // partial cleanup; | |
128 | // (b) distinguish the case where the type `Foo` has a | |
129 | // destructor, in which case creating an instance | |
130 | // as a whole "arms" the destructor, and you can't | |
131 | // write individual fields; and, | |
132 | // (c) handle the case where the type Foo has no | |
133 | // fields. We don't want `let x: ();` to compile | |
134 | // to the same MIR as `let x = ();`. | |
135 | ||
136 | // first process the set of fields | |
137 | let fields: Vec<_> = | |
138 | fields.into_iter() | |
139 | .map(|f| unpack!(block = this.as_operand(block, f))) | |
140 | .collect(); | |
141 | ||
142 | block.and(Rvalue::Aggregate(AggregateKind::Vec, fields)) | |
143 | } | |
144 | ExprKind::Tuple { fields } => { // see (*) above | |
145 | // first process the set of fields | |
146 | let fields: Vec<_> = | |
147 | fields.into_iter() | |
148 | .map(|f| unpack!(block = this.as_operand(block, f))) | |
149 | .collect(); | |
150 | ||
151 | block.and(Rvalue::Aggregate(AggregateKind::Tuple, fields)) | |
152 | } | |
153 | ExprKind::Closure { closure_id, substs, upvars } => { // see (*) above | |
154 | let upvars = | |
155 | upvars.into_iter() | |
156 | .map(|upvar| unpack!(block = this.as_operand(block, upvar))) | |
157 | .collect(); | |
158 | block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars)) | |
159 | } | |
7453a54e SL |
160 | ExprKind::Adt { |
161 | adt_def, variant_index, substs, fields, base | |
162 | } => { // see (*) above | |
92a42be0 SL |
163 | // first process the set of fields that were provided |
164 | // (evaluating them in order given by user) | |
e9174d1e SL |
165 | let fields_map: FnvHashMap<_, _> = |
166 | fields.into_iter() | |
167 | .map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr)))) | |
168 | .collect(); | |
169 | ||
92a42be0 SL |
170 | let field_names = this.hir.all_fields(adt_def, variant_index); |
171 | ||
7453a54e SL |
172 | let fields = if let Some(FruInfo { base, field_types }) = base { |
173 | let base = unpack!(block = this.as_lvalue(block, base)); | |
174 | ||
175 | // MIR does not natively support FRU, so for each | |
176 | // base-supplied field, generate an operand that | |
177 | // reads it from the base. | |
e9174d1e | 178 | field_names.into_iter() |
7453a54e SL |
179 | .zip(field_types.into_iter()) |
180 | .map(|(n, ty)| match fields_map.get(&n) { | |
181 | Some(v) => v.clone(), | |
182 | None => Operand::Consume(base.clone().field(n, ty)) | |
183 | }) | |
184 | .collect() | |
185 | } else { | |
186 | field_names.iter().map(|n| fields_map[n].clone()).collect() | |
187 | }; | |
e9174d1e SL |
188 | |
189 | block.and(Rvalue::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs), | |
190 | fields)) | |
191 | } | |
192 | ExprKind::Literal { .. } | | |
193 | ExprKind::Block { .. } | | |
194 | ExprKind::Match { .. } | | |
195 | ExprKind::If { .. } | | |
196 | ExprKind::Loop { .. } | | |
197 | ExprKind::LogicalOp { .. } | | |
198 | ExprKind::Call { .. } | | |
199 | ExprKind::Field { .. } | | |
200 | ExprKind::Deref { .. } | | |
201 | ExprKind::Index { .. } | | |
202 | ExprKind::VarRef { .. } | | |
203 | ExprKind::SelfRef | | |
204 | ExprKind::Assign { .. } | | |
205 | ExprKind::AssignOp { .. } | | |
206 | ExprKind::Break { .. } | | |
207 | ExprKind::Continue { .. } | | |
208 | ExprKind::Return { .. } | | |
209 | ExprKind::StaticRef { .. } => { | |
210 | // these do not have corresponding `Rvalue` variants, | |
211 | // so make an operand and then return that | |
212 | debug_assert!(match Category::of(&expr.kind) { | |
213 | Some(Category::Rvalue(RvalueFunc::AsRvalue)) => false, | |
214 | _ => true, | |
215 | }); | |
216 | let operand = unpack!(block = this.as_operand(block, expr)); | |
217 | block.and(Rvalue::Use(operand)) | |
218 | } | |
219 | } | |
220 | } | |
221 | } |