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