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