]>
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 | use hair::*; | |
3157f602 | 12 | use rustc_data_structures::indexed_vec::Idx; |
92a42be0 SL |
13 | use hair::cx::Cx; |
14 | use hair::cx::block; | |
15 | use hair::cx::to_ref::ToRef; | |
c30ab7b3 | 16 | use rustc::hir::def::{Def, CtorKind}; |
94b46f34 | 17 | use rustc::mir::interpret::GlobalId; |
83c7162d | 18 | use rustc::ty::{self, AdtKind, Ty}; |
2c00a5a8 | 19 | use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; |
a7813a04 | 20 | use rustc::ty::cast::CastKind as TyCastKind; |
54a0048b | 21 | use rustc::hir; |
abe05a73 | 22 | use rustc::hir::def_id::LocalDefId; |
2c00a5a8 | 23 | use rustc::mir::{BorrowKind}; |
b039eaaf SL |
24 | |
25 | impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { | |
26 | type Output = Expr<'tcx>; | |
27 | ||
a7813a04 | 28 | fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> { |
ea8adc8c XL |
29 | let temp_lifetime = cx.region_scope_tree.temporary_scope(self.hir_id.local_id); |
30 | let expr_scope = region::Scope::Node(self.hir_id.local_id); | |
e9174d1e | 31 | |
a7813a04 | 32 | debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); |
e9174d1e | 33 | |
a7813a04 | 34 | let mut expr = make_mirror_unadjusted(cx, self); |
7453a54e | 35 | |
e9174d1e | 36 | // Now apply adjustments, if any. |
7cac9316 XL |
37 | for adjustment in cx.tables().expr_adjustments(self) { |
38 | debug!("make_mirror: expr={:?} applying adjustment={:?}", | |
39 | expr, | |
40 | adjustment); | |
41 | expr = apply_adjustment(cx, self, expr, adjustment); | |
e9174d1e SL |
42 | } |
43 | ||
44 | // Next, wrap this up in the expr's scope. | |
45 | expr = Expr { | |
3b2f2976 | 46 | temp_lifetime, |
e9174d1e SL |
47 | ty: expr.ty, |
48 | span: self.span, | |
b039eaaf | 49 | kind: ExprKind::Scope { |
ea8adc8c | 50 | region_scope: expr_scope, |
b039eaaf | 51 | value: expr.to_ref(), |
ea8adc8c | 52 | lint_level: cx.lint_level_of(self.id), |
b039eaaf | 53 | }, |
e9174d1e SL |
54 | }; |
55 | ||
56 | // Finally, create a destruction scope, if any. | |
ea8adc8c XL |
57 | if let Some(region_scope) = |
58 | cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id) { | |
59 | expr = Expr { | |
60 | temp_lifetime, | |
61 | ty: expr.ty, | |
62 | span: self.span, | |
63 | kind: ExprKind::Scope { | |
64 | region_scope, | |
65 | value: expr.to_ref(), | |
66 | lint_level: LintLevel::Inherited, | |
67 | }, | |
68 | }; | |
69 | } | |
e9174d1e SL |
70 | |
71 | // OK, all done! | |
72 | expr | |
73 | } | |
74 | } | |
75 | ||
7cac9316 XL |
76 | fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, |
77 | hir_expr: &'tcx hir::Expr, | |
78 | mut expr: Expr<'tcx>, | |
79 | adjustment: &Adjustment<'tcx>) | |
80 | -> Expr<'tcx> { | |
81 | let Expr { temp_lifetime, span, .. } = expr; | |
82 | let kind = match adjustment.kind { | |
83 | Adjust::ReifyFnPointer => { | |
84 | ExprKind::ReifyFnPointer { source: expr.to_ref() } | |
85 | } | |
86 | Adjust::UnsafeFnPointer => { | |
87 | ExprKind::UnsafeFnPointer { source: expr.to_ref() } | |
88 | } | |
89 | Adjust::ClosureFnPointer => { | |
90 | ExprKind::ClosureFnPointer { source: expr.to_ref() } | |
91 | } | |
92 | Adjust::NeverToAny => { | |
93 | ExprKind::NeverToAny { source: expr.to_ref() } | |
94 | } | |
95 | Adjust::MutToConstPointer => { | |
96 | ExprKind::Cast { source: expr.to_ref() } | |
97 | } | |
98 | Adjust::Deref(None) => { | |
99 | ExprKind::Deref { arg: expr.to_ref() } | |
100 | } | |
101 | Adjust::Deref(Some(deref)) => { | |
0531ce1d | 102 | let call = deref.method_call(cx.tcx(), expr.ty); |
7cac9316 XL |
103 | |
104 | expr = Expr { | |
105 | temp_lifetime, | |
106 | ty: cx.tcx.mk_ref(deref.region, | |
107 | ty::TypeAndMut { | |
108 | ty: expr.ty, | |
109 | mutbl: deref.mutbl, | |
110 | }), | |
111 | span, | |
112 | kind: ExprKind::Borrow { | |
113 | region: deref.region, | |
2c00a5a8 | 114 | borrow_kind: deref.mutbl.to_borrow_kind(), |
7cac9316 XL |
115 | arg: expr.to_ref(), |
116 | }, | |
117 | }; | |
118 | ||
ff7c6d11 | 119 | overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()]) |
7cac9316 XL |
120 | } |
121 | Adjust::Borrow(AutoBorrow::Ref(r, m)) => { | |
122 | ExprKind::Borrow { | |
123 | region: r, | |
2c00a5a8 | 124 | borrow_kind: m.to_borrow_kind(), |
7cac9316 XL |
125 | arg: expr.to_ref(), |
126 | } | |
127 | } | |
128 | Adjust::Borrow(AutoBorrow::RawPtr(m)) => { | |
129 | // Convert this to a suitable `&foo` and | |
130 | // then an unsafe coercion. Limit the region to be just this | |
131 | // expression. | |
ea8adc8c | 132 | let region = ty::ReScope(region::Scope::Node(hir_expr.hir_id.local_id)); |
7cac9316 XL |
133 | let region = cx.tcx.mk_region(region); |
134 | expr = Expr { | |
135 | temp_lifetime, | |
136 | ty: cx.tcx.mk_ref(region, | |
137 | ty::TypeAndMut { | |
138 | ty: expr.ty, | |
139 | mutbl: m, | |
140 | }), | |
141 | span, | |
142 | kind: ExprKind::Borrow { | |
3b2f2976 | 143 | region, |
2c00a5a8 | 144 | borrow_kind: m.to_borrow_kind(), |
7cac9316 XL |
145 | arg: expr.to_ref(), |
146 | }, | |
147 | }; | |
2c00a5a8 XL |
148 | let cast_expr = Expr { |
149 | temp_lifetime, | |
150 | ty: adjustment.target, | |
151 | span, | |
152 | kind: ExprKind::Cast { source: expr.to_ref() } | |
153 | }; | |
154 | ||
155 | // To ensure that both implicit and explicit coercions are | |
156 | // handled the same way, we insert an extra layer of indirection here. | |
157 | // For explicit casts (e.g. 'foo as *const T'), the source of the 'Use' | |
158 | // will be an ExprKind::Hair with the appropriate cast expression. Here, | |
159 | // we make our Use source the generated Cast from the original coercion. | |
160 | // | |
161 | // In both cases, this outer 'Use' ensures that the inner 'Cast' is handled by | |
162 | // as_operand, not by as_rvalue - causing the cast result to be stored in a temporary. | |
163 | // Ordinary, this is identical to using the cast directly as an rvalue. However, if the | |
164 | // source of the cast was previously borrowed as mutable, storing the cast in a | |
165 | // temporary gives the source a chance to expire before the cast is used. For | |
166 | // structs with a self-referential *mut ptr, this allows assignment to work as | |
167 | // expected. | |
168 | // | |
169 | // For example, consider the type 'struct Foo { field: *mut Foo }', | |
170 | // The method 'fn bar(&mut self) { self.field = self }' | |
171 | // triggers a coercion from '&mut self' to '*mut self'. In order | |
172 | // for the assignment to be valid, the implicit borrow | |
173 | // of 'self' involved in the coercion needs to end before the local | |
174 | // containing the '*mut T' is assigned to 'self.field' - otherwise, | |
175 | // we end up trying to assign to 'self.field' while we have another mutable borrow | |
176 | // active. | |
177 | // | |
178 | // We only need to worry about this kind of thing for coercions from refs to ptrs, | |
179 | // since they get rid of a borrow implicitly. | |
180 | ExprKind::Use { source: cast_expr.to_ref() } | |
7cac9316 XL |
181 | } |
182 | Adjust::Unsize => { | |
183 | ExprKind::Unsize { source: expr.to_ref() } | |
184 | } | |
185 | }; | |
186 | ||
187 | Expr { | |
188 | temp_lifetime, | |
189 | ty: adjustment.target, | |
190 | span, | |
191 | kind, | |
192 | } | |
193 | } | |
194 | ||
a7813a04 XL |
195 | fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, |
196 | expr: &'tcx hir::Expr) | |
197 | -> Expr<'tcx> { | |
32a655c1 | 198 | let expr_ty = cx.tables().expr_ty(expr); |
ea8adc8c | 199 | let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
a7813a04 XL |
200 | |
201 | let kind = match expr.node { | |
202 | // Here comes the interesting stuff: | |
8faf50e0 | 203 | hir::ExprKind::MethodCall(.., ref args) => { |
a7813a04 | 204 | // Rewrite a.b(c) into UFCS form like Trait::b(a, c) |
7cac9316 | 205 | let expr = method_callee(cx, expr, None); |
a7813a04 XL |
206 | let args = args.iter() |
207 | .map(|e| e.to_ref()) | |
208 | .collect(); | |
209 | ExprKind::Call { | |
210 | ty: expr.ty, | |
211 | fun: expr.to_ref(), | |
3b2f2976 | 212 | args, |
a7813a04 XL |
213 | } |
214 | } | |
215 | ||
8faf50e0 | 216 | hir::ExprKind::Call(ref fun, ref args) => { |
7cac9316 | 217 | if cx.tables().is_method_call(expr) { |
a7813a04 XL |
218 | // The callee is something implementing Fn, FnMut, or FnOnce. |
219 | // Find the actual method implementation being called and | |
220 | // build the appropriate UFCS call expression with the | |
221 | // callee-object as expr parameter. | |
222 | ||
223 | // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) | |
224 | ||
7cac9316 | 225 | let method = method_callee(cx, expr, None); |
a7813a04 | 226 | |
7cac9316 | 227 | let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e)); |
a7813a04 | 228 | let tupled_args = Expr { |
0531ce1d | 229 | ty: cx.tcx.mk_tup(arg_tys), |
3b2f2976 | 230 | temp_lifetime, |
a7813a04 | 231 | span: expr.span, |
476ff2be | 232 | kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() }, |
a7813a04 XL |
233 | }; |
234 | ||
235 | ExprKind::Call { | |
236 | ty: method.ty, | |
237 | fun: method.to_ref(), | |
476ff2be | 238 | args: vec![fun.to_ref(), tupled_args.to_ref()], |
a7813a04 XL |
239 | } |
240 | } else { | |
8faf50e0 XL |
241 | let adt_data = if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = |
242 | fun.node | |
243 | { | |
244 | // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. | |
476ff2be SL |
245 | expr_ty.ty_adt_def().and_then(|adt_def| { |
246 | match path.def { | |
c30ab7b3 | 247 | Def::VariantCtor(variant_id, CtorKind::Fn) => { |
a7813a04 | 248 | Some((adt_def, adt_def.variant_index_with_id(variant_id))) |
476ff2be SL |
249 | } |
250 | Def::StructCtor(_, CtorKind::Fn) => Some((adt_def, 0)), | |
251 | _ => None, | |
a7813a04 XL |
252 | } |
253 | }) | |
476ff2be SL |
254 | } else { |
255 | None | |
256 | }; | |
a7813a04 | 257 | if let Some((adt_def, index)) = adt_data { |
3b2f2976 | 258 | let substs = cx.tables().node_substs(fun.hir_id); |
476ff2be SL |
259 | let field_refs = args.iter() |
260 | .enumerate() | |
261 | .map(|(idx, e)| { | |
262 | FieldExprRef { | |
263 | name: Field::new(idx), | |
264 | expr: e.to_ref(), | |
265 | } | |
266 | }) | |
267 | .collect(); | |
a7813a04 | 268 | ExprKind::Adt { |
3b2f2976 XL |
269 | adt_def, |
270 | substs, | |
a7813a04 XL |
271 | variant_index: index, |
272 | fields: field_refs, | |
476ff2be | 273 | base: None, |
a7813a04 XL |
274 | } |
275 | } else { | |
276 | ExprKind::Call { | |
3b2f2976 | 277 | ty: cx.tables().node_id_to_type(fun.hir_id), |
a7813a04 XL |
278 | fun: fun.to_ref(), |
279 | args: args.to_ref(), | |
280 | } | |
281 | } | |
282 | } | |
283 | } | |
284 | ||
8faf50e0 | 285 | hir::ExprKind::AddrOf(mutbl, ref expr) => { |
a7813a04 | 286 | let region = match expr_ty.sty { |
94b46f34 | 287 | ty::TyRef(r, _, _) => r, |
a7813a04 XL |
288 | _ => span_bug!(expr.span, "type of & not region"), |
289 | }; | |
290 | ExprKind::Borrow { | |
3b2f2976 | 291 | region, |
2c00a5a8 | 292 | borrow_kind: mutbl.to_borrow_kind(), |
a7813a04 XL |
293 | arg: expr.to_ref(), |
294 | } | |
295 | } | |
296 | ||
8faf50e0 | 297 | hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk }, |
a7813a04 | 298 | |
8faf50e0 | 299 | hir::ExprKind::Assign(ref lhs, ref rhs) => { |
a7813a04 XL |
300 | ExprKind::Assign { |
301 | lhs: lhs.to_ref(), | |
302 | rhs: rhs.to_ref(), | |
303 | } | |
304 | } | |
305 | ||
8faf50e0 | 306 | hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => { |
7cac9316 XL |
307 | if cx.tables().is_method_call(expr) { |
308 | overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) | |
a7813a04 XL |
309 | } else { |
310 | ExprKind::AssignOp { | |
311 | op: bin_op(op.node), | |
312 | lhs: lhs.to_ref(), | |
313 | rhs: rhs.to_ref(), | |
314 | } | |
315 | } | |
316 | } | |
317 | ||
8faf50e0 | 318 | hir::ExprKind::Lit(ref lit) => ExprKind::Literal { |
0531ce1d XL |
319 | literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), |
320 | }, | |
a7813a04 | 321 | |
8faf50e0 | 322 | hir::ExprKind::Binary(op, ref lhs, ref rhs) => { |
7cac9316 XL |
323 | if cx.tables().is_method_call(expr) { |
324 | overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) | |
a7813a04 XL |
325 | } else { |
326 | // FIXME overflow | |
327 | match (op.node, cx.constness) { | |
328 | // FIXME(eddyb) use logical ops in constants when | |
329 | // they can handle that kind of control-flow. | |
8faf50e0 | 330 | (hir::BinOpKind::And, hir::Constness::Const) => { |
a7813a04 XL |
331 | ExprKind::Binary { |
332 | op: BinOp::BitAnd, | |
333 | lhs: lhs.to_ref(), | |
334 | rhs: rhs.to_ref(), | |
335 | } | |
336 | } | |
8faf50e0 | 337 | (hir::BinOpKind::Or, hir::Constness::Const) => { |
a7813a04 XL |
338 | ExprKind::Binary { |
339 | op: BinOp::BitOr, | |
340 | lhs: lhs.to_ref(), | |
341 | rhs: rhs.to_ref(), | |
342 | } | |
343 | } | |
344 | ||
8faf50e0 | 345 | (hir::BinOpKind::And, hir::Constness::NotConst) => { |
a7813a04 XL |
346 | ExprKind::LogicalOp { |
347 | op: LogicalOp::And, | |
348 | lhs: lhs.to_ref(), | |
349 | rhs: rhs.to_ref(), | |
350 | } | |
351 | } | |
8faf50e0 | 352 | (hir::BinOpKind::Or, hir::Constness::NotConst) => { |
a7813a04 XL |
353 | ExprKind::LogicalOp { |
354 | op: LogicalOp::Or, | |
355 | lhs: lhs.to_ref(), | |
356 | rhs: rhs.to_ref(), | |
357 | } | |
358 | } | |
359 | ||
360 | _ => { | |
361 | let op = bin_op(op.node); | |
362 | ExprKind::Binary { | |
3b2f2976 | 363 | op, |
a7813a04 XL |
364 | lhs: lhs.to_ref(), |
365 | rhs: rhs.to_ref(), | |
366 | } | |
367 | } | |
368 | } | |
369 | } | |
370 | } | |
371 | ||
8faf50e0 | 372 | hir::ExprKind::Index(ref lhs, ref index) => { |
7cac9316 | 373 | if cx.tables().is_method_call(expr) { |
ff7c6d11 | 374 | overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()]) |
a7813a04 XL |
375 | } else { |
376 | ExprKind::Index { | |
377 | lhs: lhs.to_ref(), | |
378 | index: index.to_ref(), | |
379 | } | |
380 | } | |
381 | } | |
382 | ||
8faf50e0 | 383 | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => { |
7cac9316 | 384 | if cx.tables().is_method_call(expr) { |
ff7c6d11 | 385 | overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()]) |
a7813a04 XL |
386 | } else { |
387 | ExprKind::Deref { arg: arg.to_ref() } | |
388 | } | |
389 | } | |
390 | ||
8faf50e0 | 391 | hir::ExprKind::Unary(hir::UnOp::UnNot, ref arg) => { |
7cac9316 XL |
392 | if cx.tables().is_method_call(expr) { |
393 | overloaded_operator(cx, expr, vec![arg.to_ref()]) | |
a7813a04 XL |
394 | } else { |
395 | ExprKind::Unary { | |
396 | op: UnOp::Not, | |
397 | arg: arg.to_ref(), | |
398 | } | |
399 | } | |
400 | } | |
401 | ||
8faf50e0 | 402 | hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => { |
7cac9316 XL |
403 | if cx.tables().is_method_call(expr) { |
404 | overloaded_operator(cx, expr, vec![arg.to_ref()]) | |
a7813a04 | 405 | } else { |
8faf50e0 | 406 | if let hir::ExprKind::Lit(ref lit) = arg.node { |
0531ce1d XL |
407 | ExprKind::Literal { |
408 | literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), | |
409 | } | |
a7813a04 XL |
410 | } else { |
411 | ExprKind::Unary { | |
412 | op: UnOp::Neg, | |
413 | arg: arg.to_ref(), | |
414 | } | |
415 | } | |
416 | } | |
417 | } | |
418 | ||
8faf50e0 | 419 | hir::ExprKind::Struct(ref qpath, ref fields, ref base) => { |
a7813a04 | 420 | match expr_ty.sty { |
476ff2be SL |
421 | ty::TyAdt(adt, substs) => { |
422 | match adt.adt_kind() { | |
423 | AdtKind::Struct | AdtKind::Union => { | |
476ff2be SL |
424 | ExprKind::Adt { |
425 | adt_def: adt, | |
426 | variant_index: 0, | |
3b2f2976 | 427 | substs, |
83c7162d | 428 | fields: field_refs(cx, fields), |
476ff2be SL |
429 | base: base.as_ref().map(|base| { |
430 | FruInfo { | |
431 | base: base.to_ref(), | |
3b2f2976 XL |
432 | field_types: cx.tables() |
433 | .fru_field_types()[expr.hir_id] | |
434 | .clone(), | |
476ff2be SL |
435 | } |
436 | }), | |
437 | } | |
9e0c209e | 438 | } |
476ff2be SL |
439 | AdtKind::Enum => { |
440 | let def = match *qpath { | |
441 | hir::QPath::Resolved(_, ref path) => path.def, | |
442 | hir::QPath::TypeRelative(..) => Def::Err, | |
443 | }; | |
444 | match def { | |
445 | Def::Variant(variant_id) => { | |
446 | assert!(base.is_none()); | |
447 | ||
448 | let index = adt.variant_index_with_id(variant_id); | |
476ff2be SL |
449 | ExprKind::Adt { |
450 | adt_def: adt, | |
451 | variant_index: index, | |
3b2f2976 | 452 | substs, |
83c7162d | 453 | fields: field_refs(cx, fields), |
476ff2be SL |
454 | base: None, |
455 | } | |
456 | } | |
457 | _ => { | |
458 | span_bug!(expr.span, "unexpected def: {:?}", def); | |
9e0c209e | 459 | } |
a7813a04 | 460 | } |
a7813a04 XL |
461 | } |
462 | } | |
476ff2be | 463 | } |
a7813a04 | 464 | _ => { |
476ff2be SL |
465 | span_bug!(expr.span, |
466 | "unexpected type for struct literal: {:?}", | |
467 | expr_ty); | |
a7813a04 XL |
468 | } |
469 | } | |
470 | } | |
471 | ||
8faf50e0 | 472 | hir::ExprKind::Closure(..) => { |
32a655c1 | 473 | let closure_ty = cx.tables().expr_ty(expr); |
94b46f34 XL |
474 | let (def_id, substs, movability) = match closure_ty.sty { |
475 | ty::TyClosure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs), None), | |
476 | ty::TyGenerator(def_id, substs, movability) => { | |
477 | (def_id, UpvarSubsts::Generator(substs), Some(movability)) | |
478 | } | |
a7813a04 | 479 | _ => { |
476ff2be | 480 | span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); |
a7813a04 XL |
481 | } |
482 | }; | |
483 | let upvars = cx.tcx.with_freevars(expr.id, |freevars| { | |
484 | freevars.iter() | |
476ff2be SL |
485 | .zip(substs.upvar_tys(def_id, cx.tcx)) |
486 | .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty)) | |
a7813a04 XL |
487 | .collect() |
488 | }); | |
489 | ExprKind::Closure { | |
490 | closure_id: def_id, | |
3b2f2976 XL |
491 | substs, |
492 | upvars, | |
94b46f34 | 493 | movability, |
a7813a04 XL |
494 | } |
495 | } | |
496 | ||
8faf50e0 | 497 | hir::ExprKind::Path(ref qpath) => { |
3b2f2976 | 498 | let def = cx.tables().qpath_def(qpath, expr.hir_id); |
476ff2be | 499 | convert_path_expr(cx, expr, def) |
a7813a04 XL |
500 | } |
501 | ||
8faf50e0 | 502 | hir::ExprKind::InlineAsm(ref asm, ref outputs, ref inputs) => { |
a7813a04 | 503 | ExprKind::InlineAsm { |
3b2f2976 | 504 | asm, |
a7813a04 | 505 | outputs: outputs.to_ref(), |
476ff2be | 506 | inputs: inputs.to_ref(), |
a7813a04 XL |
507 | } |
508 | } | |
509 | ||
510 | // Now comes the rote stuff: | |
8faf50e0 | 511 | hir::ExprKind::Repeat(ref v, ref count) => { |
94b46f34 | 512 | let def_id = cx.tcx.hir.local_def_id(count.id); |
3b2f2976 | 513 | let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id); |
0531ce1d XL |
514 | let instance = ty::Instance::resolve( |
515 | cx.tcx.global_tcx(), | |
516 | cx.param_env, | |
517 | def_id, | |
518 | substs, | |
519 | ).unwrap(); | |
520 | let global_id = GlobalId { | |
521 | instance, | |
522 | promoted: None | |
523 | }; | |
94b46f34 XL |
524 | let span = cx.tcx.def_span(def_id); |
525 | let count = match cx.tcx.at(span).const_eval(cx.param_env.and(global_id)) { | |
526 | Ok(cv) => cv.unwrap_usize(cx.tcx), | |
0531ce1d | 527 | Err(e) => { |
94b46f34 | 528 | e.report_as_error(cx.tcx.at(span), "could not evaluate array length"); |
0531ce1d XL |
529 | 0 |
530 | }, | |
32a655c1 SL |
531 | }; |
532 | ||
476ff2be SL |
533 | ExprKind::Repeat { |
534 | value: v.to_ref(), | |
3b2f2976 | 535 | count, |
a7813a04 | 536 | } |
476ff2be | 537 | } |
8faf50e0 XL |
538 | hir::ExprKind::Ret(ref v) => ExprKind::Return { value: v.to_ref() }, |
539 | hir::ExprKind::Break(dest, ref value) => { | |
cc61c64b | 540 | match dest.target_id { |
94b46f34 | 541 | Ok(target_id) => ExprKind::Break { |
ea8adc8c | 542 | label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(target_id).local_id), |
8bb4bdeb XL |
543 | value: value.to_ref(), |
544 | }, | |
94b46f34 | 545 | Err(err) => bug!("invalid loop id for break: {}", err) |
476ff2be SL |
546 | } |
547 | } | |
8faf50e0 | 548 | hir::ExprKind::Continue(dest) => { |
cc61c64b | 549 | match dest.target_id { |
94b46f34 | 550 | Ok(loop_id) => ExprKind::Continue { |
ea8adc8c | 551 | label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(loop_id).local_id), |
8bb4bdeb | 552 | }, |
94b46f34 | 553 | Err(err) => bug!("invalid loop id for continue: {}", err) |
476ff2be SL |
554 | } |
555 | } | |
8faf50e0 | 556 | hir::ExprKind::Match(ref discr, ref arms, _) => { |
476ff2be SL |
557 | ExprKind::Match { |
558 | discriminant: discr.to_ref(), | |
559 | arms: arms.iter().map(|a| convert_arm(cx, a)).collect(), | |
560 | } | |
561 | } | |
8faf50e0 | 562 | hir::ExprKind::If(ref cond, ref then, ref otherwise) => { |
476ff2be SL |
563 | ExprKind::If { |
564 | condition: cond.to_ref(), | |
cc61c64b | 565 | then: then.to_ref(), |
476ff2be SL |
566 | otherwise: otherwise.to_ref(), |
567 | } | |
568 | } | |
8faf50e0 | 569 | hir::ExprKind::While(ref cond, ref body, _) => { |
476ff2be SL |
570 | ExprKind::Loop { |
571 | condition: Some(cond.to_ref()), | |
572 | body: block::to_expr_ref(cx, body), | |
573 | } | |
574 | } | |
8faf50e0 | 575 | hir::ExprKind::Loop(ref body, _, _) => { |
476ff2be SL |
576 | ExprKind::Loop { |
577 | condition: None, | |
578 | body: block::to_expr_ref(cx, body), | |
579 | } | |
580 | } | |
8faf50e0 | 581 | hir::ExprKind::Field(ref source, ..) => { |
476ff2be SL |
582 | ExprKind::Field { |
583 | lhs: source.to_ref(), | |
83c7162d | 584 | name: Field::new(cx.tcx.field_index(expr.id, cx.tables)), |
476ff2be | 585 | } |
a7813a04 | 586 | } |
8faf50e0 | 587 | hir::ExprKind::Cast(ref source, _) => { |
a7813a04 XL |
588 | // Check to see if this cast is a "coercion cast", where the cast is actually done |
589 | // using a coercion (or is a no-op). | |
3b2f2976 | 590 | if let Some(&TyCastKind::CoercionCast) = cx.tables() |
0531ce1d XL |
591 | .cast_kinds() |
592 | .get(source.hir_id) { | |
1bb2cb6e SL |
593 | // Convert the lexpr to a vexpr. |
594 | ExprKind::Use { source: source.to_ref() } | |
a7813a04 | 595 | } else { |
0531ce1d XL |
596 | // check whether this is casting an enum variant discriminant |
597 | // to prevent cycles, we refer to the discriminant initializer | |
598 | // which is always an integer and thus doesn't need to know the | |
599 | // enum's layout (or its tag type) to compute it during const eval | |
600 | // Example: | |
601 | // enum Foo { | |
602 | // A, | |
603 | // B = A as isize + 4, | |
604 | // } | |
605 | // The correct solution would be to add symbolic computations to miri, | |
606 | // so we wouldn't have to compute and store the actual value | |
8faf50e0 | 607 | let var = if let hir::ExprKind::Path(ref qpath) = source.node { |
0531ce1d XL |
608 | let def = cx.tables().qpath_def(qpath, source.hir_id); |
609 | cx | |
610 | .tables() | |
611 | .node_id_to_type(source.hir_id) | |
612 | .ty_adt_def() | |
613 | .and_then(|adt_def| { | |
614 | match def { | |
615 | Def::VariantCtor(variant_id, CtorKind::Const) => { | |
616 | let idx = adt_def.variant_index_with_id(variant_id); | |
617 | let (d, o) = adt_def.discriminant_def_for_variant(idx); | |
618 | use rustc::ty::util::IntTypeExt; | |
94b46f34 XL |
619 | let ty = adt_def.repr.discr_type(); |
620 | let ty = ty.to_ty(cx.tcx()); | |
0531ce1d XL |
621 | Some((d, o, ty)) |
622 | } | |
623 | _ => None, | |
624 | } | |
625 | }) | |
626 | } else { | |
627 | None | |
628 | }; | |
629 | let source = if let Some((did, offset, ty)) = var { | |
8faf50e0 | 630 | let mk_const = |literal| Expr { |
0531ce1d XL |
631 | temp_lifetime, |
632 | ty, | |
633 | span: expr.span, | |
8faf50e0 | 634 | kind: ExprKind::Literal { literal }, |
0531ce1d | 635 | }.to_ref(); |
94b46f34 XL |
636 | let offset = mk_const(ty::Const::from_bits( |
637 | cx.tcx, | |
638 | offset as u128, | |
639 | cx.param_env.and(ty), | |
640 | )); | |
0531ce1d XL |
641 | match did { |
642 | Some(did) => { | |
643 | // in case we are offsetting from a computed discriminant | |
644 | // and not the beginning of discriminants (which is always `0`) | |
645 | let substs = Substs::identity_for_item(cx.tcx(), did); | |
94b46f34 | 646 | let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty)); |
0531ce1d XL |
647 | let bin = ExprKind::Binary { |
648 | op: BinOp::Add, | |
649 | lhs, | |
650 | rhs: offset, | |
651 | }; | |
652 | Expr { | |
653 | temp_lifetime, | |
654 | ty, | |
655 | span: expr.span, | |
656 | kind: bin, | |
657 | }.to_ref() | |
658 | }, | |
659 | None => offset, | |
660 | } | |
661 | } else { | |
662 | source.to_ref() | |
663 | }; | |
664 | ExprKind::Cast { source } | |
a7813a04 XL |
665 | } |
666 | } | |
8faf50e0 XL |
667 | hir::ExprKind::Type(ref source, _) => return source.make_mirror(cx), |
668 | hir::ExprKind::Box(ref value) => { | |
a7813a04 XL |
669 | ExprKind::Box { |
670 | value: value.to_ref(), | |
476ff2be SL |
671 | } |
672 | } | |
8faf50e0 XL |
673 | hir::ExprKind::Array(ref fields) => ExprKind::Array { fields: fields.to_ref() }, |
674 | hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, | |
ea8adc8c | 675 | |
8faf50e0 | 676 | hir::ExprKind::Yield(ref v) => ExprKind::Yield { value: v.to_ref() }, |
a7813a04 XL |
677 | }; |
678 | ||
679 | Expr { | |
3b2f2976 | 680 | temp_lifetime, |
a7813a04 XL |
681 | ty: expr_ty, |
682 | span: expr.span, | |
3b2f2976 | 683 | kind, |
a7813a04 XL |
684 | } |
685 | } | |
686 | ||
687 | fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, | |
688 | expr: &hir::Expr, | |
7cac9316 | 689 | custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>) |
a7813a04 | 690 | -> Expr<'tcx> { |
ea8adc8c | 691 | let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
7cac9316 | 692 | let (def_id, substs) = custom_callee.unwrap_or_else(|| { |
8faf50e0 XL |
693 | if let Some(def) = cx.tables().type_dependent_defs().get(expr.hir_id) { |
694 | (def.def_id(), cx.tables().node_substs(expr.hir_id)) | |
695 | } else { | |
696 | span_bug!(expr.span, "no type-dependent def for method callee") | |
697 | } | |
7cac9316 | 698 | }); |
ea8adc8c | 699 | let ty = cx.tcx().mk_fn_def(def_id, substs); |
e9174d1e | 700 | Expr { |
3b2f2976 | 701 | temp_lifetime, |
ea8adc8c | 702 | ty, |
e9174d1e SL |
703 | span: expr.span, |
704 | kind: ExprKind::Literal { | |
8faf50e0 | 705 | literal: ty::Const::zero_sized(cx.tcx(), ty), |
b039eaaf | 706 | }, |
e9174d1e SL |
707 | } |
708 | } | |
709 | ||
2c00a5a8 XL |
710 | trait ToBorrowKind { fn to_borrow_kind(&self) -> BorrowKind; } |
711 | ||
712 | impl ToBorrowKind for AutoBorrowMutability { | |
713 | fn to_borrow_kind(&self) -> BorrowKind { | |
83c7162d | 714 | use rustc::ty::adjustment::AllowTwoPhase; |
2c00a5a8 XL |
715 | match *self { |
716 | AutoBorrowMutability::Mutable { allow_two_phase_borrow } => | |
83c7162d XL |
717 | BorrowKind::Mut { allow_two_phase_borrow: match allow_two_phase_borrow { |
718 | AllowTwoPhase::Yes => true, | |
719 | AllowTwoPhase::No => false | |
720 | }}, | |
2c00a5a8 XL |
721 | AutoBorrowMutability::Immutable => |
722 | BorrowKind::Shared, | |
723 | } | |
724 | } | |
725 | } | |
726 | ||
727 | impl ToBorrowKind for hir::Mutability { | |
728 | fn to_borrow_kind(&self) -> BorrowKind { | |
729 | match *self { | |
730 | hir::MutMutable => BorrowKind::Mut { allow_two_phase_borrow: false }, | |
731 | hir::MutImmutable => BorrowKind::Shared, | |
732 | } | |
e9174d1e SL |
733 | } |
734 | } | |
735 | ||
476ff2be | 736 | fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> { |
b039eaaf | 737 | Arm { |
ea8adc8c | 738 | patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(), |
b039eaaf SL |
739 | guard: arm.guard.to_ref(), |
740 | body: arm.body.to_ref(), | |
ea8adc8c XL |
741 | // BUG: fix this |
742 | lint_level: LintLevel::Inherited, | |
b039eaaf | 743 | } |
e9174d1e SL |
744 | } |
745 | ||
a7813a04 | 746 | fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, |
476ff2be SL |
747 | expr: &'tcx hir::Expr, |
748 | def: Def) | |
a7813a04 | 749 | -> ExprKind<'tcx> { |
3b2f2976 | 750 | let substs = cx.tables().node_substs(expr.hir_id); |
cc61c64b | 751 | match def { |
c30ab7b3 | 752 | // A regular function, constructor function or a constant. |
0531ce1d XL |
753 | Def::Fn(_) | |
754 | Def::Method(_) | | |
755 | Def::StructCtor(_, CtorKind::Fn) | | |
756 | Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal { | |
8faf50e0 XL |
757 | literal: ty::Const::zero_sized( |
758 | cx.tcx, | |
759 | cx.tables().node_id_to_type(expr.hir_id), | |
760 | ), | |
cc61c64b XL |
761 | }, |
762 | ||
476ff2be | 763 | Def::Const(def_id) | |
cc61c64b | 764 | Def::AssociatedConst(def_id) => ExprKind::Literal { |
8faf50e0 XL |
765 | literal: ty::Const::unevaluated( |
766 | cx.tcx, | |
767 | def_id, | |
768 | substs, | |
769 | cx.tables().node_id_to_type(expr.hir_id), | |
770 | ), | |
cc61c64b | 771 | }, |
c30ab7b3 SL |
772 | |
773 | Def::StructCtor(def_id, CtorKind::Const) | | |
774 | Def::VariantCtor(def_id, CtorKind::Const) => { | |
3b2f2976 | 775 | match cx.tables().node_id_to_type(expr.hir_id).sty { |
c30ab7b3 SL |
776 | // A unit struct/variant which is used as a value. |
777 | // We return a completely different ExprKind here to account for this special case. | |
476ff2be | 778 | ty::TyAdt(adt_def, substs) => { |
cc61c64b | 779 | ExprKind::Adt { |
3b2f2976 | 780 | adt_def, |
476ff2be | 781 | variant_index: adt_def.variant_index_with_id(def_id), |
3b2f2976 | 782 | substs, |
476ff2be SL |
783 | fields: vec![], |
784 | base: None, | |
785 | } | |
786 | } | |
787 | ref sty => bug!("unexpected sty: {:?}", sty), | |
c30ab7b3 SL |
788 | } |
789 | } | |
9cc50fc6 | 790 | |
cc61c64b | 791 | Def::Static(node_id, _) => ExprKind::StaticRef { id: node_id }, |
e9174d1e | 792 | |
cc61c64b | 793 | Def::Local(..) | Def::Upvar(..) => convert_var(cx, expr, def), |
e9174d1e | 794 | |
3157f602 | 795 | _ => span_bug!(expr.span, "def `{:?}` not yet implemented", def), |
e9174d1e SL |
796 | } |
797 | } | |
798 | ||
a7813a04 XL |
799 | fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, |
800 | expr: &'tcx hir::Expr, | |
801 | def: Def) | |
802 | -> ExprKind<'tcx> { | |
ea8adc8c | 803 | let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
e9174d1e SL |
804 | |
805 | match def { | |
ea8adc8c | 806 | Def::Local(id) => ExprKind::VarRef { id }, |
e9174d1e | 807 | |
ea8adc8c | 808 | Def::Upvar(var_id, index, closure_expr_id) => { |
476ff2be | 809 | debug!("convert_var(upvar({:?}, {:?}, {:?}))", |
ea8adc8c | 810 | var_id, |
476ff2be SL |
811 | index, |
812 | closure_expr_id); | |
ea8adc8c XL |
813 | let var_hir_id = cx.tcx.hir.node_to_hir_id(var_id); |
814 | let var_ty = cx.tables().node_id_to_type(var_hir_id); | |
e9174d1e | 815 | |
e9174d1e | 816 | // FIXME free regions in closures are not right |
3b2f2976 XL |
817 | let closure_ty = cx.tables() |
818 | .node_id_to_type(cx.tcx.hir.node_to_hir_id(closure_expr_id)); | |
e9174d1e SL |
819 | |
820 | // FIXME we're just hard-coding the idea that the | |
821 | // signature will be &self or &mut self and hence will | |
822 | // have a bound region with number 0 | |
7cac9316 XL |
823 | let closure_def_id = cx.tcx.hir.local_def_id(closure_expr_id); |
824 | let region = ty::ReFree(ty::FreeRegion { | |
825 | scope: closure_def_id, | |
b039eaaf SL |
826 | bound_region: ty::BoundRegion::BrAnon(0), |
827 | }); | |
828 | let region = cx.tcx.mk_region(region); | |
829 | ||
ff7c6d11 XL |
830 | let self_expr = if let ty::TyClosure(_, closure_substs) = closure_ty.sty { |
831 | match cx.infcx.closure_kind(closure_def_id, closure_substs).unwrap() { | |
ea8adc8c XL |
832 | ty::ClosureKind::Fn => { |
833 | let ref_closure_ty = cx.tcx.mk_ref(region, | |
834 | ty::TypeAndMut { | |
835 | ty: closure_ty, | |
836 | mutbl: hir::MutImmutable, | |
837 | }); | |
838 | Expr { | |
839 | ty: closure_ty, | |
840 | temp_lifetime: temp_lifetime, | |
841 | span: expr.span, | |
842 | kind: ExprKind::Deref { | |
843 | arg: Expr { | |
844 | ty: ref_closure_ty, | |
845 | temp_lifetime, | |
846 | span: expr.span, | |
847 | kind: ExprKind::SelfRef, | |
848 | } | |
849 | .to_ref(), | |
850 | }, | |
851 | } | |
e9174d1e | 852 | } |
ea8adc8c XL |
853 | ty::ClosureKind::FnMut => { |
854 | let ref_closure_ty = cx.tcx.mk_ref(region, | |
855 | ty::TypeAndMut { | |
856 | ty: closure_ty, | |
857 | mutbl: hir::MutMutable, | |
858 | }); | |
859 | Expr { | |
860 | ty: closure_ty, | |
861 | temp_lifetime, | |
862 | span: expr.span, | |
863 | kind: ExprKind::Deref { | |
864 | arg: Expr { | |
865 | ty: ref_closure_ty, | |
866 | temp_lifetime, | |
867 | span: expr.span, | |
868 | kind: ExprKind::SelfRef, | |
869 | }.to_ref(), | |
870 | }, | |
871 | } | |
e9174d1e | 872 | } |
ea8adc8c XL |
873 | ty::ClosureKind::FnOnce => { |
874 | Expr { | |
875 | ty: closure_ty, | |
876 | temp_lifetime, | |
877 | span: expr.span, | |
878 | kind: ExprKind::SelfRef, | |
879 | } | |
e9174d1e SL |
880 | } |
881 | } | |
ea8adc8c XL |
882 | } else { |
883 | Expr { | |
884 | ty: closure_ty, | |
885 | temp_lifetime, | |
886 | span: expr.span, | |
887 | kind: ExprKind::SelfRef, | |
888 | } | |
e9174d1e SL |
889 | }; |
890 | ||
891 | // at this point we have `self.n`, which loads up the upvar | |
b039eaaf SL |
892 | let field_kind = ExprKind::Field { |
893 | lhs: self_expr.to_ref(), | |
92a42be0 | 894 | name: Field::new(index), |
b039eaaf | 895 | }; |
e9174d1e SL |
896 | |
897 | // ...but the upvar might be an `&T` or `&mut T` capture, at which | |
898 | // point we need an implicit deref | |
b039eaaf | 899 | let upvar_id = ty::UpvarId { |
ea8adc8c | 900 | var_id: var_hir_id, |
abe05a73 | 901 | closure_expr_id: LocalDefId::from_def_id(closure_def_id), |
b039eaaf | 902 | }; |
041b39d2 | 903 | match cx.tables().upvar_capture(upvar_id) { |
e9174d1e | 904 | ty::UpvarCapture::ByValue => field_kind, |
7453a54e | 905 | ty::UpvarCapture::ByRef(borrow) => { |
e9174d1e SL |
906 | ExprKind::Deref { |
907 | arg: Expr { | |
3b2f2976 | 908 | temp_lifetime, |
32a655c1 SL |
909 | ty: cx.tcx.mk_ref(borrow.region, |
910 | ty::TypeAndMut { | |
911 | ty: var_ty, | |
912 | mutbl: borrow.kind.to_mutbl_lossy(), | |
913 | }), | |
914 | span: expr.span, | |
915 | kind: field_kind, | |
916 | }.to_ref(), | |
e9174d1e SL |
917 | } |
918 | } | |
919 | } | |
920 | } | |
921 | ||
54a0048b | 922 | _ => span_bug!(expr.span, "type of & not region"), |
e9174d1e SL |
923 | } |
924 | } | |
925 | ||
926 | ||
8faf50e0 | 927 | fn bin_op(op: hir::BinOpKind) -> BinOp { |
e9174d1e | 928 | match op { |
8faf50e0 XL |
929 | hir::BinOpKind::Add => BinOp::Add, |
930 | hir::BinOpKind::Sub => BinOp::Sub, | |
931 | hir::BinOpKind::Mul => BinOp::Mul, | |
932 | hir::BinOpKind::Div => BinOp::Div, | |
933 | hir::BinOpKind::Rem => BinOp::Rem, | |
934 | hir::BinOpKind::BitXor => BinOp::BitXor, | |
935 | hir::BinOpKind::BitAnd => BinOp::BitAnd, | |
936 | hir::BinOpKind::BitOr => BinOp::BitOr, | |
937 | hir::BinOpKind::Shl => BinOp::Shl, | |
938 | hir::BinOpKind::Shr => BinOp::Shr, | |
939 | hir::BinOpKind::Eq => BinOp::Eq, | |
940 | hir::BinOpKind::Lt => BinOp::Lt, | |
941 | hir::BinOpKind::Le => BinOp::Le, | |
942 | hir::BinOpKind::Ne => BinOp::Ne, | |
943 | hir::BinOpKind::Ge => BinOp::Ge, | |
944 | hir::BinOpKind::Gt => BinOp::Gt, | |
54a0048b | 945 | _ => bug!("no equivalent for ast binop {:?}", op), |
e9174d1e SL |
946 | } |
947 | } | |
948 | ||
a7813a04 XL |
949 | fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, |
950 | expr: &'tcx hir::Expr, | |
7cac9316 | 951 | args: Vec<ExprRef<'tcx>>) |
a7813a04 | 952 | -> ExprKind<'tcx> { |
7cac9316 | 953 | let fun = method_callee(cx, expr, None); |
e9174d1e | 954 | ExprKind::Call { |
9cc50fc6 | 955 | ty: fun.ty, |
e9174d1e | 956 | fun: fun.to_ref(), |
7cac9316 | 957 | args, |
e9174d1e SL |
958 | } |
959 | } | |
960 | ||
ff7c6d11 | 961 | fn overloaded_place<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, |
a7813a04 | 962 | expr: &'tcx hir::Expr, |
ff7c6d11 | 963 | place_ty: Ty<'tcx>, |
7cac9316 XL |
964 | custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>, |
965 | args: Vec<ExprRef<'tcx>>) | |
a7813a04 | 966 | -> ExprKind<'tcx> { |
e9174d1e SL |
967 | // For an overloaded *x or x[y] expression of type T, the method |
968 | // call returns an &T and we must add the deref so that the types | |
ff7c6d11 | 969 | // line up (this is because `*x` and `x[y]` represent places): |
e9174d1e | 970 | |
7cac9316 XL |
971 | let recv_ty = match args[0] { |
972 | ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e), | |
973 | ExprRef::Mirror(ref e) => e.ty | |
974 | }; | |
975 | ||
976 | // Reconstruct the output assuming it's a reference with the | |
977 | // same region and mutability as the receiver. This holds for | |
978 | // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. | |
94b46f34 XL |
979 | let (region, mutbl) = match recv_ty.sty { |
980 | ty::TyRef(region, _, mutbl) => (region, mutbl), | |
ff7c6d11 | 981 | _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"), |
7cac9316 XL |
982 | }; |
983 | let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { | |
ff7c6d11 | 984 | ty: place_ty, |
94b46f34 | 985 | mutbl, |
7cac9316 | 986 | }); |
e9174d1e SL |
987 | |
988 | // construct the complete expression `foo()` for the overloaded call, | |
989 | // which will yield the &T type | |
ea8adc8c | 990 | let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
7cac9316 | 991 | let fun = method_callee(cx, expr, custom_callee); |
e9174d1e | 992 | let ref_expr = Expr { |
3b2f2976 | 993 | temp_lifetime, |
e9174d1e SL |
994 | ty: ref_ty, |
995 | span: expr.span, | |
7cac9316 XL |
996 | kind: ExprKind::Call { |
997 | ty: fun.ty, | |
998 | fun: fun.to_ref(), | |
999 | args, | |
1000 | }, | |
e9174d1e SL |
1001 | }; |
1002 | ||
1003 | // construct and return a deref wrapper `*foo()` | |
1004 | ExprKind::Deref { arg: ref_expr.to_ref() } | |
1005 | } | |
1006 | ||
a7813a04 XL |
1007 | fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, |
1008 | closure_expr: &'tcx hir::Expr, | |
1009 | freevar: &hir::Freevar, | |
1010 | freevar_ty: Ty<'tcx>) | |
1011 | -> ExprRef<'tcx> { | |
ea8adc8c | 1012 | let var_hir_id = cx.tcx.hir.node_to_hir_id(freevar.var_id()); |
b039eaaf | 1013 | let upvar_id = ty::UpvarId { |
ea8adc8c | 1014 | var_id: var_hir_id, |
abe05a73 | 1015 | closure_expr_id: cx.tcx.hir.local_def_id(closure_expr.id).to_local(), |
b039eaaf | 1016 | }; |
041b39d2 | 1017 | let upvar_capture = cx.tables().upvar_capture(upvar_id); |
ea8adc8c XL |
1018 | let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); |
1019 | let var_ty = cx.tables().node_id_to_type(var_hir_id); | |
b039eaaf | 1020 | let captured_var = Expr { |
3b2f2976 | 1021 | temp_lifetime, |
b039eaaf SL |
1022 | ty: var_ty, |
1023 | span: closure_expr.span, | |
1024 | kind: convert_var(cx, closure_expr, freevar.def), | |
1025 | }; | |
e9174d1e | 1026 | match upvar_capture { |
476ff2be | 1027 | ty::UpvarCapture::ByValue => captured_var.to_ref(), |
e9174d1e SL |
1028 | ty::UpvarCapture::ByRef(upvar_borrow) => { |
1029 | let borrow_kind = match upvar_borrow.kind { | |
1030 | ty::BorrowKind::ImmBorrow => BorrowKind::Shared, | |
1031 | ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique, | |
2c00a5a8 | 1032 | ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false } |
e9174d1e SL |
1033 | }; |
1034 | Expr { | |
3b2f2976 | 1035 | temp_lifetime, |
32a655c1 SL |
1036 | ty: freevar_ty, |
1037 | span: closure_expr.span, | |
1038 | kind: ExprKind::Borrow { | |
1039 | region: upvar_borrow.region, | |
3b2f2976 | 1040 | borrow_kind, |
32a655c1 SL |
1041 | arg: captured_var.to_ref(), |
1042 | }, | |
1043 | }.to_ref() | |
e9174d1e SL |
1044 | } |
1045 | } | |
1046 | } | |
1047 | ||
9cc50fc6 | 1048 | /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef. |
83c7162d XL |
1049 | fn field_refs<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, |
1050 | fields: &'tcx [hir::Field]) | |
1051 | -> Vec<FieldExprRef<'tcx>> { | |
92a42be0 | 1052 | fields.iter() |
476ff2be SL |
1053 | .map(|field| { |
1054 | FieldExprRef { | |
83c7162d | 1055 | name: Field::new(cx.tcx.field_index(field.id, cx.tables)), |
476ff2be SL |
1056 | expr: field.expr.to_ref(), |
1057 | } | |
1058 | }) | |
1059 | .collect() | |
92a42be0 | 1060 | } |