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