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