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