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