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