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