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