]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/tcx/expr.rs
f15470e7851d41b133e5470748154e94506888ab
[rust.git] / src / librustc_mir / tcx / 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 repr::*;
13 use rustc_data_structures::fnv::FnvHashMap;
14 use std::rc::Rc;
15 use tcx::Cx;
16 use tcx::block;
17 use tcx::pattern::PatNode;
18 use tcx::rustc::front::map;
19 use tcx::rustc::middle::def;
20 use tcx::rustc::middle::def_id::DefId;
21 use tcx::rustc::middle::region::CodeExtent;
22 use tcx::rustc::middle::pat_util;
23 use tcx::rustc::middle::ty::{self, Ty};
24 use tcx::rustc_front::hir;
25 use tcx::rustc_front::util as hir_util;
26 use tcx::syntax::codemap::Span;
27 use tcx::syntax::parse::token;
28 use tcx::syntax::ptr::P;
29 use tcx::to_ref::ToRef;
30
31 impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
32     type Output = Expr<Cx<'a,'tcx>>;
33
34     fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Expr<Cx<'a,'tcx>> {
35         debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
36
37         let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)!
38
39         let kind = match self.node {
40             // Here comes the interesting stuff:
41
42             hir::ExprMethodCall(_, _, ref args) => {
43                 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
44                 let expr = method_callee(cx, self, ty::MethodCall::expr(self.id));
45                 let args = args.iter()
46                                .map(|e| e.to_ref())
47                                .collect();
48                 ExprKind::Call {
49                     fun: expr.to_ref(),
50                     args: args
51                 }
52             }
53
54             hir::ExprAddrOf(mutbl, ref expr) => {
55                 let region = match expr_ty.sty {
56                     ty::TyRef(r, _) => r,
57                     _ => cx.tcx.sess.span_bug(expr.span, "type of & not region")
58                 };
59                 ExprKind::Borrow { region: *region,
60                                    borrow_kind: to_borrow_kind(mutbl),
61                                    arg: expr.to_ref() }
62             }
63
64             hir::ExprBlock(ref blk) => {
65                 ExprKind::Block {
66                     body: &**blk
67                 }
68             }
69
70             hir::ExprAssign(ref lhs, ref rhs) => {
71                 ExprKind::Assign {
72                     lhs: lhs.to_ref(),
73                     rhs: rhs.to_ref(),
74                 }
75             }
76
77             hir::ExprAssignOp(op, ref lhs, ref rhs) => {
78                 let op = bin_op(op.node);
79                 ExprKind::AssignOp {
80                     op: op,
81                     lhs: lhs.to_ref(),
82                     rhs: rhs.to_ref(),
83                 }
84             }
85
86             hir::ExprLit(ref lit) => {
87                 let literal = convert_literal(cx, self.span, expr_ty, lit);
88                 ExprKind::Literal { literal: literal }
89             }
90
91             hir::ExprBinary(op, ref lhs, ref rhs) => {
92                 if cx.tcx.is_method_call(self.id) {
93                     let pass_args = if hir_util::is_by_value_binop(op.node) {
94                         PassArgs::ByValue
95                     } else {
96                         PassArgs::ByRef
97                     };
98                     overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
99                                         pass_args, lhs.to_ref(), vec![rhs])
100                 } else {
101                     // FIXME overflow
102                     match op.node {
103                         hir::BinOp_::BiAnd => {
104                             ExprKind::LogicalOp { op: LogicalOp::And,
105                                                   lhs: lhs.to_ref(),
106                                                   rhs: rhs.to_ref() }
107                         }
108                         hir::BinOp_::BiOr => {
109                             ExprKind::LogicalOp { op: LogicalOp::Or,
110                                                   lhs: lhs.to_ref(),
111                                                   rhs: rhs.to_ref() }
112                         }
113                         _ => {
114                             let op = bin_op(op.node);
115                             ExprKind::Binary { op: op,
116                                                lhs: lhs.to_ref(),
117                                                rhs: rhs.to_ref() }
118                         }
119                     }
120                 }
121             }
122
123             hir::ExprIndex(ref lhs, ref index) => {
124                 if cx.tcx.is_method_call(self.id) {
125                     overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id),
126                                       PassArgs::ByValue, lhs.to_ref(), vec![index])
127                 } else {
128                     ExprKind::Index { lhs: lhs.to_ref(),
129                                       index: index.to_ref() }
130                 }
131             }
132
133             hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
134                 if cx.tcx.is_method_call(self.id) {
135                     overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id),
136                                       PassArgs::ByValue, arg.to_ref(), vec![])
137                 } else {
138                     ExprKind::Deref { arg: arg.to_ref() }
139                 }
140             }
141
142             hir::ExprUnary(hir::UnOp::UnUniq, ref arg) => {
143                 assert!(!cx.tcx.is_method_call(self.id));
144                 ExprKind::Box { place: None, value: arg.to_ref() }
145             }
146
147             hir::ExprUnary(op, ref arg) => {
148                 if cx.tcx.is_method_call(self.id) {
149                     overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
150                                         PassArgs::ByValue, arg.to_ref(), vec![])
151                 } else {
152                     // FIXME overflow
153                     let op = match op {
154                         hir::UnOp::UnNot => UnOp::Not,
155                         hir::UnOp::UnNeg => UnOp::Neg,
156                         hir::UnOp::UnUniq | hir::UnOp::UnDeref => {
157                             cx.tcx.sess.span_bug(
158                                 self.span,
159                                 &format!("operator should have been handled elsewhere {:?}", op));
160                         }
161                     };
162                     ExprKind::Unary { op: op, arg: arg.to_ref() }
163                 }
164             }
165
166             hir::ExprStruct(_, ref fields, ref base) => {
167                 match expr_ty.sty {
168                     ty::TyStruct(adt, substs) => {
169                         ExprKind::Adt {
170                             adt_def: adt,
171                             variant_index: 0,
172                             substs: substs,
173                             fields: fields.to_ref(),
174                             base: base.to_ref(),
175                         }
176                     }
177                     ty::TyEnum(adt, substs) => {
178                         match cx.tcx.def_map.borrow()[&self.id].full_def() {
179                             def::DefVariant(enum_id, variant_id, true) => {
180                                 debug_assert!(adt.did == enum_id);
181                                 let index = adt.variant_index_with_id(variant_id);
182                                 ExprKind::Adt {
183                                     adt_def: adt,
184                                     variant_index: index,
185                                     substs: substs,
186                                     fields: fields.to_ref(),
187                                     base: base.to_ref(),
188                                 }
189                             }
190                             ref def => {
191                                 cx.tcx.sess.span_bug(
192                                     self.span,
193                                     &format!("unexpected def: {:?}", def));
194                             }
195                         }
196                     }
197                     _ => {
198                         cx.tcx.sess.span_bug(
199                             self.span,
200                             &format!("unexpected type for struct literal: {:?}", expr_ty));
201                     }
202                 }
203             }
204
205             hir::ExprClosure(..) => {
206                 let closure_ty = cx.tcx.expr_ty(self);
207                 let (def_id, substs) = match closure_ty.sty {
208                     ty::TyClosure(def_id, ref substs) => (def_id, substs),
209                     _ => {
210                         cx.tcx.sess.span_bug(self.span,
211                                           &format!("closure expr w/o closure type: {:?}",
212                                                    closure_ty));
213                     }
214                 };
215                 let upvars = cx.tcx.with_freevars(self.id, |freevars| {
216                     freevars.iter()
217                             .enumerate()
218                             .map(|(i, fv)| capture_freevar(cx, self, fv, substs.upvar_tys[i]))
219                             .collect()
220                 });
221                 ExprKind::Closure {
222                     closure_id: def_id,
223                     substs: &**substs,
224                     upvars: upvars,
225                 }
226             }
227
228             hir::ExprRange(ref start, ref end) => {
229                 let range_ty = cx.tcx.expr_ty(self);
230                 let (adt_def, substs) = match range_ty.sty {
231                     ty::TyStruct(adt_def, substs) => (adt_def, substs),
232                     _ => {
233                         cx.tcx.sess.span_bug(
234                             self.span,
235                             &format!("unexpanded ast"));
236                     }
237                 };
238
239                 let field_expr_ref = |s: &'tcx P<hir::Expr>, nm: &str| {
240                     FieldExprRef { name: Field::Named(token::intern(nm)),
241                                    expr: s.to_ref() }
242                 };
243
244                 let start_field = start.as_ref()
245                                        .into_iter()
246                                        .map(|s| field_expr_ref(s, "start"));
247
248                 let end_field = end.as_ref()
249                                    .into_iter()
250                                    .map(|e| field_expr_ref(e, "end"));
251
252                 ExprKind::Adt { adt_def: adt_def,
253                                 variant_index: 0,
254                                 substs: substs,
255                                 fields: start_field.chain(end_field).collect(),
256                                 base: None }
257             }
258
259             hir::ExprPath(..) => {
260                 convert_path_expr(cx, self)
261             }
262
263             hir::ExprInlineAsm(ref asm) => {
264                 ExprKind::InlineAsm { asm: asm }
265             }
266
267             // Now comes the rote stuff:
268
269             hir::ExprParen(ref p) =>
270                 ExprKind::Paren { arg: p.to_ref() },
271             hir::ExprRepeat(ref v, ref c) =>
272                 ExprKind::Repeat { value: v.to_ref(), count: c.to_ref() },
273             hir::ExprRet(ref v) =>
274                 ExprKind::Return { value: v.to_ref() },
275             hir::ExprBreak(label) =>
276                 ExprKind::Break { label: label.map(|_| loop_label(cx, self)) },
277             hir::ExprAgain(label) =>
278                 ExprKind::Continue { label: label.map(|_| loop_label(cx, self)) },
279             hir::ExprMatch(ref discr, ref arms, _) =>
280                 ExprKind::Match { discriminant: discr.to_ref(),
281                                   arms: arms.iter().map(|a| convert_arm(cx, a)).collect() },
282             hir::ExprIf(ref cond, ref then, ref otherwise) =>
283                 ExprKind::If { condition: cond.to_ref(),
284                                then: block::to_expr_ref(cx, then),
285                                otherwise: otherwise.to_ref() },
286             hir::ExprWhile(ref cond, ref body, _) =>
287                 ExprKind::Loop { condition: Some(cond.to_ref()),
288                                  body: block::to_expr_ref(cx, body) },
289             hir::ExprLoop(ref body, _) =>
290                 ExprKind::Loop { condition: None,
291                                  body: block::to_expr_ref(cx, body) },
292             hir::ExprField(ref source, ident) =>
293                 ExprKind::Field { lhs: source.to_ref(),
294                                   name: Field::Named(ident.node.name) },
295             hir::ExprTupField(ref source, ident) =>
296                 ExprKind::Field { lhs: source.to_ref(),
297                                   name: Field::Indexed(ident.node) },
298             hir::ExprCast(ref source, _) =>
299                 ExprKind::Cast { source: source.to_ref() },
300             hir::ExprBox(ref place, ref value) =>
301                 ExprKind::Box { place: place.to_ref(), value: value.to_ref() },
302             hir::ExprVec(ref fields) =>
303                 ExprKind::Vec { fields: fields.to_ref() },
304             hir::ExprTup(ref fields) =>
305                 ExprKind::Tuple { fields: fields.to_ref() },
306             hir::ExprCall(ref fun, ref args) =>
307                 ExprKind::Call { fun: fun.to_ref(), args: args.to_ref() },
308         };
309
310         let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id);
311         let expr_extent = cx.tcx.region_maps.node_extent(self.id);
312
313         let mut expr = Expr {
314             temp_lifetime: temp_lifetime,
315             ty: expr_ty,
316             span: self.span,
317             kind: kind,
318         };
319
320         // Now apply adjustments, if any.
321         match cx.tcx.tables.borrow().adjustments.get(&self.id) {
322             None => { }
323             Some(&ty::adjustment::AdjustReifyFnPointer) => {
324                 let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
325                 expr = Expr {
326                     temp_lifetime: temp_lifetime,
327                     ty: adjusted_ty,
328                     span: self.span,
329                     kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
330                 };
331             }
332             Some(&ty::adjustment::AdjustUnsafeFnPointer) => {
333                 let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
334                 expr = Expr {
335                     temp_lifetime: temp_lifetime,
336                     ty: adjusted_ty,
337                     span: self.span,
338                     kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
339                 };
340             }
341             Some(&ty::adjustment::AdjustDerefRef(ref adj)) => {
342                 for i in 0..adj.autoderefs {
343                     let i = i as u32;
344                     let adjusted_ty =
345                         expr.ty.adjust_for_autoderef(
346                             cx.tcx,
347                             self.id,
348                             self.span,
349                             i,
350                             |mc| cx.tcx.tables.borrow().method_map.get(&mc).map(|m| m.ty));
351                     let kind = if cx.tcx.is_overloaded_autoderef(self.id, i) {
352                         overloaded_lvalue(cx, self, ty::MethodCall::autoderef(self.id, i),
353                                           PassArgs::ByValue, expr.to_ref(), vec![])
354                     } else {
355                         ExprKind::Deref { arg: expr.to_ref() }
356                     };
357                     expr = Expr {
358                         temp_lifetime: temp_lifetime,
359                         ty: adjusted_ty,
360                         span: self.span,
361                         kind: kind
362                     };
363                 }
364
365                 if let Some(target) = adj.unsize {
366                     expr = Expr {
367                         temp_lifetime: temp_lifetime,
368                         ty: target,
369                         span: self.span,
370                         kind: ExprKind::Unsize { source: expr.to_ref() }
371                     };
372                 } else if let Some(autoref) = adj.autoref {
373                     let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
374                     match autoref {
375                         ty::adjustment::AutoPtr(r, m) => {
376                             expr = Expr {
377                                 temp_lifetime: temp_lifetime,
378                                 ty: adjusted_ty,
379                                 span: self.span,
380                                 kind: ExprKind::Borrow { region: *r,
381                                                          borrow_kind: to_borrow_kind(m),
382                                                          arg: expr.to_ref() }
383                             };
384                         }
385                         ty::adjustment::AutoUnsafe(m) => {
386                             // Convert this to a suitable `&foo` and
387                             // then an unsafe coercion. Limit the region to be just this
388                             // expression.
389                             let region = ty::ReScope(expr_extent);
390                             let region = cx.tcx.mk_region(region);
391                             expr = Expr {
392                                 temp_lifetime: temp_lifetime,
393                                 ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, mutbl: m }),
394                                 span: self.span,
395                                 kind: ExprKind::Borrow { region: *region,
396                                                          borrow_kind: to_borrow_kind(m),
397                                                          arg: expr.to_ref() }
398                             };
399                             expr = Expr {
400                                 temp_lifetime: temp_lifetime,
401                                 ty: adjusted_ty,
402                                 span: self.span,
403                                 kind: ExprKind::Cast { source: expr.to_ref() }
404                             };
405                         }
406                     }
407                 }
408             }
409         }
410
411         // Next, wrap this up in the expr's scope.
412         expr = Expr {
413             temp_lifetime: temp_lifetime,
414             ty: expr.ty,
415             span: self.span,
416             kind: ExprKind::Scope { extent: expr_extent,
417                                     value: expr.to_ref() }
418         };
419
420         // Finally, create a destruction scope, if any.
421         if let Some(extent) = cx.tcx.region_maps.opt_destruction_extent(self.id) {
422             expr = Expr {
423                 temp_lifetime: temp_lifetime,
424                 ty: expr.ty,
425                 span: self.span,
426                 kind: ExprKind::Scope { extent: extent, value: expr.to_ref() }
427             };
428         }
429
430         // OK, all done!
431         expr
432     }
433 }
434
435 fn method_callee<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
436                              expr: &hir::Expr,
437                              method_call: ty::MethodCall)
438                              -> Expr<Cx<'a,'tcx>> {
439     let tables = cx.tcx.tables.borrow();
440     let callee = &tables.method_map[&method_call];
441     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
442     Expr {
443         temp_lifetime: temp_lifetime,
444         ty: callee.ty,
445         span: expr.span,
446         kind: ExprKind::Literal {
447             literal: Literal::Item {
448                 def_id: callee.def_id,
449                 substs: callee.substs,
450             }
451         }
452     }
453 }
454
455 fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
456     match m {
457         hir::MutMutable => BorrowKind::Mut,
458         hir::MutImmutable => BorrowKind::Shared,
459     }
460 }
461
462 fn convert_literal<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
463                                expr_span: Span,
464                                expr_ty: Ty<'tcx>,
465                                literal: &hir::Lit)
466                                -> Literal<Cx<'a,'tcx>>
467 {
468     use repr::IntegralBits::*;
469     match (&literal.node, &expr_ty.sty) {
470         (&hir::LitStr(ref text, _), _) =>
471             Literal::String { value: text.clone() },
472         (&hir::LitByteStr(ref bytes), _) =>
473             Literal::Bytes { value: bytes.clone() },
474         (&hir::LitByte(c), _) =>
475             Literal::Uint { bits: B8, value: c as u64 },
476         (&hir::LitChar(c), _) =>
477             Literal::Char { c: c },
478         (&hir::LitInt(v, _), &ty::TyUint(hir::TyU8)) =>
479             Literal::Uint { bits: B8, value: v },
480         (&hir::LitInt(v, _), &ty::TyUint(hir::TyU16)) =>
481             Literal::Uint { bits: B16, value: v },
482         (&hir::LitInt(v, _), &ty::TyUint(hir::TyU32)) =>
483             Literal::Uint { bits: B32, value: v },
484         (&hir::LitInt(v, _), &ty::TyUint(hir::TyU64)) =>
485             Literal::Uint { bits: B64, value: v },
486         (&hir::LitInt(v, _), &ty::TyUint(hir::TyUs)) =>
487             Literal::Uint { bits: BSize, value: v },
488         (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI8)) =>
489             Literal::Int { bits: B8, value: -(v as i64) },
490         (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI16)) =>
491             Literal::Int { bits: B16, value: -(v as i64) },
492         (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI32)) =>
493             Literal::Int { bits: B32, value: -(v as i64) },
494         (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI64)) =>
495             Literal::Int { bits: B64, value: -(v as i64) },
496         (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyIs)) =>
497             Literal::Int { bits: BSize, value: -(v as i64) },
498         (&hir::LitInt(v, _), &ty::TyInt(hir::TyI8)) =>
499             Literal::Int { bits: B8, value: v as i64 },
500         (&hir::LitInt(v, _), &ty::TyInt(hir::TyI16)) =>
501             Literal::Int { bits: B16, value: v as i64 },
502         (&hir::LitInt(v, _), &ty::TyInt(hir::TyI32)) =>
503             Literal::Int { bits: B32, value: v as i64 },
504         (&hir::LitInt(v, _), &ty::TyInt(hir::TyI64)) =>
505             Literal::Int { bits: B64, value: v as i64 },
506         (&hir::LitInt(v, _), &ty::TyInt(hir::TyIs)) =>
507             Literal::Int { bits: BSize, value: v as i64 },
508         (&hir::LitFloat(ref v, _), &ty::TyFloat(hir::TyF32)) |
509         (&hir::LitFloatUnsuffixed(ref v), &ty::TyFloat(hir::TyF32)) =>
510             Literal::Float { bits: FloatBits::F32, value: v.parse::<f64>().unwrap() },
511         (&hir::LitFloat(ref v, _), &ty::TyFloat(hir::TyF64)) |
512         (&hir::LitFloatUnsuffixed(ref v), &ty::TyFloat(hir::TyF64)) =>
513             Literal::Float { bits: FloatBits::F64, value: v.parse::<f64>().unwrap() },
514         (&hir::LitBool(v), _) =>
515             Literal::Bool { value: v },
516         (ref l, ref t) =>
517             cx.tcx.sess.span_bug(
518                 expr_span,
519                 &format!("Invalid literal/type combination: {:?},{:?}", l, t))
520     }
521 }
522
523 fn convert_arm<'a,'tcx:'a>(cx: &Cx<'a,'tcx>, arm: &'tcx hir::Arm) -> Arm<Cx<'a,'tcx>> {
524     let map = if arm.pats.len() == 1 {
525         None
526     } else {
527         let mut map = FnvHashMap();
528         pat_util::pat_bindings(&cx.tcx.def_map, &arm.pats[0], |_, p_id, _, path| {
529             map.insert(path.node, p_id);
530         });
531         Some(Rc::new(map))
532     };
533
534     Arm { patterns: arm.pats.iter().map(|p| PatNode::new(p, map.clone()).to_ref()).collect(),
535           guard: arm.guard.to_ref(),
536           body: arm.body.to_ref() }
537 }
538
539 fn convert_path_expr<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
540                                  expr: &'tcx hir::Expr)
541                                  -> ExprKind<Cx<'a,'tcx>>
542 {
543     let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
544     match cx.tcx.def_map.borrow()[&expr.id].full_def() {
545         def::DefVariant(_, def_id, false) |
546         def::DefStruct(def_id) |
547         def::DefFn(def_id, _) |
548         def::DefConst(def_id) |
549         def::DefMethod(def_id) |
550         def::DefAssociatedConst(def_id) =>
551             ExprKind::Literal {
552                 literal: Literal::Item { def_id: def_id, substs: substs }
553             },
554
555         def::DefStatic(node_id, _) =>
556             ExprKind::StaticRef {
557                 id: node_id,
558             },
559
560         def @ def::DefLocal(..) |
561         def @ def::DefUpvar(..) =>
562             convert_var(cx, expr, def),
563
564         def =>
565             cx.tcx.sess.span_bug(
566                 expr.span,
567                 &format!("def `{:?}` not yet implemented", def)),
568     }
569 }
570
571 fn convert_var<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
572                            expr: &'tcx hir::Expr,
573                            def: def::Def)
574                            -> ExprKind<Cx<'a,'tcx>>
575 {
576     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
577
578     match def {
579         def::DefLocal(node_id) => {
580             ExprKind::VarRef {
581                 id: node_id,
582             }
583         }
584
585         def::DefUpvar(id_var, index, closure_expr_id) => {
586             debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
587             let var_ty = cx.tcx.node_id_to_type(id_var);
588
589             let body_id = match cx.tcx.map.find(closure_expr_id) {
590                 Some(map::NodeExpr(expr)) => {
591                     match expr.node {
592                         hir::ExprClosure(_, _, ref body) => body.id,
593                         _ => {
594                             cx.tcx.sess.span_bug(expr.span,
595                                               &format!("closure expr is not a closure expr"));
596                         }
597                     }
598                 }
599                 _ => {
600                     cx.tcx.sess.span_bug(expr.span,
601                                       &format!("ast-map has garbage for closure expr"));
602                 }
603             };
604
605             // FIXME free regions in closures are not right
606             let closure_ty =
607                 cx.tcx.node_id_to_type(closure_expr_id);
608
609             // FIXME we're just hard-coding the idea that the
610             // signature will be &self or &mut self and hence will
611             // have a bound region with number 0
612             let region =
613                 ty::Region::ReFree(
614                     ty::FreeRegion {
615                         scope: cx.tcx.region_maps.node_extent(body_id),
616                         bound_region: ty::BoundRegion::BrAnon(0)
617                     });
618             let region =
619                 cx.tcx.mk_region(region);
620
621             let self_expr = match cx.tcx.closure_kind(DefId::local(closure_expr_id)) {
622                 ty::ClosureKind::FnClosureKind => {
623                     let ref_closure_ty =
624                         cx.tcx.mk_ref(region,
625                                    ty::TypeAndMut { ty: closure_ty,
626                                                     mutbl: hir::MutImmutable });
627                     Expr {
628                         ty: closure_ty,
629                         temp_lifetime: temp_lifetime,
630                         span: expr.span,
631                         kind: ExprKind::Deref {
632                             arg: Expr {
633                                 ty: ref_closure_ty,
634                                 temp_lifetime: temp_lifetime,
635                                 span: expr.span,
636                                 kind: ExprKind::SelfRef
637                             }.to_ref()
638                         }
639                     }
640                 }
641                 ty::ClosureKind::FnMutClosureKind => {
642                     let ref_closure_ty =
643                         cx.tcx.mk_ref(region,
644                                    ty::TypeAndMut { ty: closure_ty,
645                                                     mutbl: hir::MutMutable });
646                     Expr {
647                         ty: closure_ty,
648                         temp_lifetime: temp_lifetime,
649                         span: expr.span,
650                         kind: ExprKind::Deref {
651                             arg: Expr {
652                                 ty: ref_closure_ty,
653                                 temp_lifetime: temp_lifetime,
654                                 span: expr.span,
655                                 kind: ExprKind::SelfRef
656                             }.to_ref()
657                         }
658                     }
659                 }
660                 ty::ClosureKind::FnOnceClosureKind => {
661                     Expr {
662                         ty: closure_ty,
663                         temp_lifetime: temp_lifetime,
664                         span: expr.span,
665                         kind: ExprKind::SelfRef
666                     }
667                 }
668             };
669
670             // at this point we have `self.n`, which loads up the upvar
671             let field_kind =
672                 ExprKind::Field { lhs: self_expr.to_ref(),
673                                   name: Field::Indexed(index) };
674
675             // ...but the upvar might be an `&T` or `&mut T` capture, at which
676             // point we need an implicit deref
677             let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr_id };
678             let upvar_capture = match cx.tcx.upvar_capture(upvar_id) {
679                 Some(c) => c,
680                 None => {
681                     cx.tcx.sess.span_bug(
682                         expr.span,
683                         &format!("no upvar_capture for {:?}", upvar_id));
684                 }
685             };
686             match upvar_capture {
687                 ty::UpvarCapture::ByValue => field_kind,
688                 ty::UpvarCapture::ByRef(_) => {
689                     ExprKind::Deref {
690                         arg: Expr {
691                             temp_lifetime: temp_lifetime,
692                             ty: var_ty,
693                             span: expr.span,
694                             kind: field_kind,
695                         }.to_ref()
696                     }
697                 }
698             }
699         }
700
701         _ => cx.tcx.sess.span_bug(expr.span, "type of & not region")
702     }
703 }
704
705
706 fn bin_op(op: hir::BinOp_) -> BinOp {
707     match op {
708         hir::BinOp_::BiAdd => BinOp::Add,
709         hir::BinOp_::BiSub => BinOp::Sub,
710         hir::BinOp_::BiMul => BinOp::Mul,
711         hir::BinOp_::BiDiv => BinOp::Div,
712         hir::BinOp_::BiRem => BinOp::Rem,
713         hir::BinOp_::BiBitXor => BinOp::BitXor,
714         hir::BinOp_::BiBitAnd => BinOp::BitAnd,
715         hir::BinOp_::BiBitOr => BinOp::BitOr,
716         hir::BinOp_::BiShl => BinOp::Shl,
717         hir::BinOp_::BiShr => BinOp::Shr,
718         hir::BinOp_::BiEq => BinOp::Eq,
719         hir::BinOp_::BiLt => BinOp::Lt,
720         hir::BinOp_::BiLe => BinOp::Le,
721         hir::BinOp_::BiNe => BinOp::Ne,
722         hir::BinOp_::BiGe => BinOp::Ge,
723         hir::BinOp_::BiGt => BinOp::Gt,
724         _ => panic!("no equivalent for ast binop {:?}", op)
725     }
726 }
727
728 enum PassArgs {
729     ByValue,
730     ByRef
731 }
732
733 fn overloaded_operator<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
734                                    expr: &'tcx hir::Expr,
735                                    method_call: ty::MethodCall,
736                                    pass_args: PassArgs,
737                                    receiver: ExprRef<Cx<'a,'tcx>>,
738                                    args: Vec<&'tcx P<hir::Expr>>)
739                                    -> ExprKind<Cx<'a,'tcx>>
740 {
741     // the receiver has all the adjustments that are needed, so we can
742     // just push a reference to it
743     let mut argrefs = vec![receiver];
744
745     // the arguments, unfortunately, do not, so if this is a ByRef
746     // operator, we have to gin up the autorefs (but by value is easy)
747     match pass_args {
748         PassArgs::ByValue => {
749             argrefs.extend(
750                 args.iter()
751                     .map(|arg| arg.to_ref()))
752         }
753
754         PassArgs::ByRef => {
755             let scope = cx.tcx.region_maps.node_extent(expr.id);
756             let region = cx.tcx.mk_region(ty::ReScope(scope));
757             let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
758             argrefs.extend(
759                 args.iter()
760                     .map(|arg| {
761                         let arg_ty = cx.tcx.expr_ty_adjusted(arg);
762                         let adjusted_ty =
763                             cx.tcx.mk_ref(region,
764                                        ty::TypeAndMut { ty: arg_ty,
765                                                         mutbl: hir::MutImmutable });
766                         Expr {
767                             temp_lifetime: temp_lifetime,
768                             ty: adjusted_ty,
769                             span: expr.span,
770                             kind: ExprKind::Borrow { region: *region,
771                                                      borrow_kind: BorrowKind::Shared,
772                                                      arg: arg.to_ref() }
773                         }.to_ref()
774                     }))
775         }
776     }
777
778     // now create the call itself
779     let fun = method_callee(cx, expr, method_call);
780     ExprKind::Call {
781         fun: fun.to_ref(),
782         args: argrefs,
783     }
784 }
785
786 fn overloaded_lvalue<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
787                                  expr: &'tcx hir::Expr,
788                                  method_call: ty::MethodCall,
789                                  pass_args: PassArgs,
790                                  receiver: ExprRef<Cx<'a,'tcx>>,
791                                  args: Vec<&'tcx P<hir::Expr>>)
792                                  -> ExprKind<Cx<'a,'tcx>>
793 {
794     // For an overloaded *x or x[y] expression of type T, the method
795     // call returns an &T and we must add the deref so that the types
796     // line up (this is because `*x` and `x[y]` represent lvalues):
797
798     // to find the type &T of the content returned by the method;
799     let tables = cx.tcx.tables.borrow();
800     let callee = &tables.method_map[&method_call];
801     let ref_ty = callee.ty.fn_ret();
802     let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap().unwrap();
803     //                                              1~~~~~   2~~~~~
804     // (1) callees always have all late-bound regions fully instantiated,
805     // (2) overloaded methods don't return `!`
806
807     // construct the complete expression `foo()` for the overloaded call,
808     // which will yield the &T type
809     let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
810     let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
811     let ref_expr = Expr {
812         temp_lifetime: temp_lifetime,
813         ty: ref_ty,
814         span: expr.span,
815         kind: ref_kind,
816     };
817
818     // construct and return a deref wrapper `*foo()`
819     ExprKind::Deref { arg: ref_expr.to_ref() }
820 }
821
822 fn capture_freevar<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
823                                closure_expr: &'tcx hir::Expr,
824                                freevar: &ty::Freevar,
825                                freevar_ty: Ty<'tcx>)
826                                -> ExprRef<Cx<'a,'tcx>> {
827     let id_var = freevar.def.def_id().node;
828     let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id };
829     let upvar_capture = cx.tcx.upvar_capture(upvar_id).unwrap();
830     let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id);
831     let var_ty = cx.tcx.node_id_to_type(id_var);
832     let captured_var = Expr { temp_lifetime: temp_lifetime,
833                               ty: var_ty,
834                               span: closure_expr.span,
835                               kind: convert_var(cx, closure_expr, freevar.def) };
836     match upvar_capture {
837         ty::UpvarCapture::ByValue => {
838             captured_var.to_ref()
839         }
840         ty::UpvarCapture::ByRef(upvar_borrow) => {
841             let borrow_kind = match upvar_borrow.kind {
842                 ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
843                 ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
844                 ty::BorrowKind::MutBorrow => BorrowKind::Mut,
845             };
846             Expr {
847                 temp_lifetime: temp_lifetime,
848                 ty: freevar_ty,
849                 span: closure_expr.span,
850                 kind: ExprKind::Borrow { region: upvar_borrow.region,
851                                          borrow_kind: borrow_kind,
852                                          arg: captured_var.to_ref() }
853             }.to_ref()
854         }
855     }
856 }
857
858 fn loop_label<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
859                           expr: &'tcx hir::Expr)
860                           -> CodeExtent
861 {
862     match cx.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
863         Some(def::DefLabel(loop_id)) => cx.tcx.region_maps.node_extent(loop_id),
864         d => {
865             cx.tcx.sess.span_bug(
866                 expr.span,
867                 &format!("loop scope resolved to {:?}", d));
868         }
869     }
870 }