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