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