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