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