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