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