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