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.
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.
12 use rustc_data_structures::indexed_vec::Idx;
13 use rustc_const_math::ConstInt;
16 use hair::cx::to_ref::ToRef;
18 use rustc::hir::def::{Def, CtorKind};
19 use rustc::middle::const_val::ConstVal;
20 use rustc::ty::{self, AdtKind, VariantDef, Ty};
21 use rustc::ty::cast::CastKind as TyCastKind;
25 impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
26 type Output = Expr<'tcx>;
28 fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
29 let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(self.id);
30 let expr_extent = cx.tcx.region_maps.node_extent(self.id);
32 debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
34 let mut expr = make_mirror_unadjusted(cx, self);
35 let adj = cx.tables().adjustments.get(&self.id).cloned();
37 debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
41 // Now apply adjustments, if any.
42 match adj.map(|adj| (adj.kind, adj.target)) {
44 Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => {
46 temp_lifetime: temp_lifetime,
47 temp_lifetime_was_shrunk: was_shrunk,
50 kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
53 Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => {
55 temp_lifetime: temp_lifetime,
56 temp_lifetime_was_shrunk: was_shrunk,
59 kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
62 Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => {
64 temp_lifetime: temp_lifetime,
65 temp_lifetime_was_shrunk: was_shrunk,
68 kind: ExprKind::ClosureFnPointer { source: expr.to_ref() },
71 Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
73 temp_lifetime: temp_lifetime,
74 temp_lifetime_was_shrunk: was_shrunk,
77 kind: ExprKind::NeverToAny { source: expr.to_ref() },
80 Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => {
82 temp_lifetime: temp_lifetime,
83 temp_lifetime_was_shrunk: was_shrunk,
86 kind: ExprKind::Cast { source: expr.to_ref() },
89 Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize },
91 for i in 0..autoderefs {
94 expr.ty.adjust_for_autoderef(cx.tcx, self.id, self.span, i, |mc| {
95 cx.tables().method_map.get(&mc).map(|m| m.ty)
97 debug!("make_mirror: autoderef #{}, adjusted_ty={:?}",
100 let method_key = ty::MethodCall::autoderef(self.id, i);
101 let meth_ty = cx.tables().method_map.get(&method_key).map(|m| m.ty);
102 let kind = if let Some(meth_ty) = meth_ty {
103 debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
105 let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
106 let (region, mutbl) = match ref_ty {
107 Some(&ty::TyS { sty: ty::TyRef(region, mt), .. }) => (region, mt.mutbl),
108 _ => span_bug!(expr.span, "autoderef returned bad type"),
112 temp_lifetime: temp_lifetime,
113 temp_lifetime_was_shrunk: was_shrunk,
114 ty: cx.tcx.mk_ref(region,
120 kind: ExprKind::Borrow {
122 borrow_kind: to_borrow_kind(mutbl),
127 overloaded_lvalue(cx,
134 debug!("make_mirror: built-in autoderef");
135 ExprKind::Deref { arg: expr.to_ref() }
138 temp_lifetime: temp_lifetime,
139 temp_lifetime_was_shrunk: was_shrunk,
146 if let Some(autoref) = autoref {
147 let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
149 ty::adjustment::AutoBorrow::Ref(r, m) => {
151 temp_lifetime: temp_lifetime,
152 temp_lifetime_was_shrunk: was_shrunk,
155 kind: ExprKind::Borrow {
157 borrow_kind: to_borrow_kind(m),
162 ty::adjustment::AutoBorrow::RawPtr(m) => {
163 // Convert this to a suitable `&foo` and
164 // then an unsafe coercion. Limit the region to be just this
166 let region = ty::ReScope(expr_extent);
167 let region = cx.tcx.mk_region(region);
169 temp_lifetime: temp_lifetime,
170 temp_lifetime_was_shrunk: was_shrunk,
171 ty: cx.tcx.mk_ref(region,
177 kind: ExprKind::Borrow {
179 borrow_kind: to_borrow_kind(m),
184 temp_lifetime: temp_lifetime,
185 temp_lifetime_was_shrunk: was_shrunk,
188 kind: ExprKind::Cast { source: expr.to_ref() },
196 temp_lifetime: temp_lifetime,
197 temp_lifetime_was_shrunk: was_shrunk,
200 kind: ExprKind::Unsize { source: expr.to_ref() },
206 // Next, wrap this up in the expr's scope.
208 temp_lifetime: temp_lifetime,
209 temp_lifetime_was_shrunk: was_shrunk,
212 kind: ExprKind::Scope {
214 value: expr.to_ref(),
218 // Finally, create a destruction scope, if any.
219 if let Some(extent) = cx.tcx.region_maps.opt_destruction_extent(self.id) {
221 temp_lifetime: temp_lifetime,
222 temp_lifetime_was_shrunk: was_shrunk,
225 kind: ExprKind::Scope {
227 value: expr.to_ref(),
237 fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
238 expr: &'tcx hir::Expr)
240 let expr_ty = cx.tables().expr_ty(expr);
241 let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id);
243 let kind = match expr.node {
244 // Here comes the interesting stuff:
245 hir::ExprMethodCall(.., ref args) => {
246 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
247 let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
248 let args = args.iter()
258 hir::ExprCall(ref fun, ref args) => {
259 if cx.tables().is_method_call(expr.id) {
260 // The callee is something implementing Fn, FnMut, or FnOnce.
261 // Find the actual method implementation being called and
262 // build the appropriate UFCS call expression with the
263 // callee-object as expr parameter.
265 // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
267 let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
269 let sig = method.ty.fn_sig();
272 .no_late_bound_regions(&sig)
273 .unwrap_or_else(|| span_bug!(expr.span, "method call has late-bound regions"));
275 assert_eq!(sig.inputs().len(), 2);
277 let tupled_args = Expr {
279 temp_lifetime: temp_lifetime,
280 temp_lifetime_was_shrunk: was_shrunk,
282 kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() },
287 fun: method.to_ref(),
288 args: vec![fun.to_ref(), tupled_args.to_ref()],
291 let adt_data = if let hir::ExprPath(hir::QPath::Resolved(_, ref path)) = fun.node {
292 // Tuple-like ADTs are represented as ExprCall. We convert them here.
293 expr_ty.ty_adt_def().and_then(|adt_def| {
295 Def::VariantCtor(variant_id, CtorKind::Fn) => {
296 Some((adt_def, adt_def.variant_index_with_id(variant_id)))
298 Def::StructCtor(_, CtorKind::Fn) => Some((adt_def, 0)),
305 if let Some((adt_def, index)) = adt_data {
306 let substs = cx.tables().node_id_item_substs(fun.id)
307 .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
308 let field_refs = args.iter()
312 name: Field::new(idx),
320 variant_index: index,
326 ty: cx.tables().node_id_to_type(fun.id),
334 hir::ExprAddrOf(mutbl, ref expr) => {
335 let region = match expr_ty.sty {
336 ty::TyRef(r, _) => r,
337 _ => span_bug!(expr.span, "type of & not region"),
341 borrow_kind: to_borrow_kind(mutbl),
346 hir::ExprBlock(ref blk) => ExprKind::Block { body: &blk },
348 hir::ExprAssign(ref lhs, ref rhs) => {
355 hir::ExprAssignOp(op, ref lhs, ref rhs) => {
356 if cx.tables().is_method_call(expr.id) {
357 let pass_args = if op.node.is_by_value() {
362 overloaded_operator(cx,
364 ty::MethodCall::expr(expr.id),
377 hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) },
379 hir::ExprBinary(op, ref lhs, ref rhs) => {
380 if cx.tables().is_method_call(expr.id) {
381 let pass_args = if op.node.is_by_value() {
386 overloaded_operator(cx,
388 ty::MethodCall::expr(expr.id),
394 match (op.node, cx.constness) {
395 // FIXME(eddyb) use logical ops in constants when
396 // they can handle that kind of control-flow.
397 (hir::BinOp_::BiAnd, hir::Constness::Const) => {
404 (hir::BinOp_::BiOr, hir::Constness::Const) => {
412 (hir::BinOp_::BiAnd, hir::Constness::NotConst) => {
413 ExprKind::LogicalOp {
419 (hir::BinOp_::BiOr, hir::Constness::NotConst) => {
420 ExprKind::LogicalOp {
428 let op = bin_op(op.node);
439 hir::ExprIndex(ref lhs, ref index) => {
440 if cx.tables().is_method_call(expr.id) {
441 overloaded_lvalue(cx,
443 ty::MethodCall::expr(expr.id),
450 index: index.to_ref(),
455 hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
456 if cx.tables().is_method_call(expr.id) {
457 overloaded_lvalue(cx,
459 ty::MethodCall::expr(expr.id),
464 ExprKind::Deref { arg: arg.to_ref() }
468 hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
469 if cx.tables().is_method_call(expr.id) {
470 overloaded_operator(cx,
472 ty::MethodCall::expr(expr.id),
484 hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
485 if cx.tables().is_method_call(expr.id) {
486 overloaded_operator(cx,
488 ty::MethodCall::expr(expr.id),
493 // FIXME runtime-overflow
494 if let hir::ExprLit(_) = arg.node {
495 ExprKind::Literal { literal: cx.const_eval_literal(expr) }
505 hir::ExprStruct(ref qpath, ref fields, ref base) => {
507 ty::TyAdt(adt, substs) => {
508 match adt.adt_kind() {
509 AdtKind::Struct | AdtKind::Union => {
510 let field_refs = field_refs(&adt.variants[0], fields);
516 base: base.as_ref().map(|base| {
519 field_types: cx.tables().fru_field_types[&expr.id].clone(),
525 let def = match *qpath {
526 hir::QPath::Resolved(_, ref path) => path.def,
527 hir::QPath::TypeRelative(..) => Def::Err,
530 Def::Variant(variant_id) => {
531 assert!(base.is_none());
533 let index = adt.variant_index_with_id(variant_id);
534 let field_refs = field_refs(&adt.variants[index], fields);
537 variant_index: index,
544 span_bug!(expr.span, "unexpected def: {:?}", def);
552 "unexpected type for struct literal: {:?}",
558 hir::ExprClosure(..) => {
559 let closure_ty = cx.tables().expr_ty(expr);
560 let (def_id, substs) = match closure_ty.sty {
561 ty::TyClosure(def_id, substs) => (def_id, substs),
563 span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
566 let upvars = cx.tcx.with_freevars(expr.id, |freevars| {
568 .zip(substs.upvar_tys(def_id, cx.tcx))
569 .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty))
579 hir::ExprPath(ref qpath) => {
580 let def = cx.tables().qpath_def(qpath, expr.id);
581 convert_path_expr(cx, expr, def)
584 hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => {
585 ExprKind::InlineAsm {
587 outputs: outputs.to_ref(),
588 inputs: inputs.to_ref(),
592 // Now comes the rote stuff:
593 hir::ExprRepeat(ref v, count) => {
594 let c = &cx.tcx.hir.body(count).value;
595 let def_id = cx.tcx.hir.body_owner_def_id(count);
596 let substs = Substs::empty();
597 let count = match cx.tcx.at(c.span).const_eval((def_id, substs)) {
598 Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
599 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
600 Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
608 hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
609 hir::ExprBreak(dest, ref value) => {
610 match dest.target_id {
611 hir::ScopeTarget::Block(target_id) |
612 hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break {
613 label: cx.tcx.region_maps.node_extent(target_id),
614 value: value.to_ref(),
616 hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
617 bug!("invalid loop id for break: {}", err)
620 hir::ExprAgain(dest) => {
621 match dest.target_id {
622 hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"),
623 hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue {
624 label: cx.tcx.region_maps.node_extent(loop_id),
626 hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
627 bug!("invalid loop id for continue: {}", err)
630 hir::ExprMatch(ref discr, ref arms, _) => {
632 discriminant: discr.to_ref(),
633 arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
636 hir::ExprIf(ref cond, ref then, ref otherwise) => {
638 condition: cond.to_ref(),
640 otherwise: otherwise.to_ref(),
643 hir::ExprWhile(ref cond, ref body, _) => {
645 condition: Some(cond.to_ref()),
646 body: block::to_expr_ref(cx, body),
649 hir::ExprLoop(ref body, _, _) => {
652 body: block::to_expr_ref(cx, body),
655 hir::ExprField(ref source, name) => {
656 let index = match cx.tables().expr_ty_adjusted(source).sty {
657 ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node),
658 ref ty => span_bug!(expr.span, "field of non-ADT: {:?}", ty),
661 index.unwrap_or_else(|| {
662 span_bug!(expr.span, "no index found for field `{}`", name.node)
665 lhs: source.to_ref(),
666 name: Field::new(index),
669 hir::ExprTupField(ref source, index) => {
671 lhs: source.to_ref(),
672 name: Field::new(index.node as usize),
675 hir::ExprCast(ref source, _) => {
676 // Check to see if this cast is a "coercion cast", where the cast is actually done
677 // using a coercion (or is a no-op).
678 if let Some(&TyCastKind::CoercionCast) = cx.tables().cast_kinds.get(&source.id) {
679 // Convert the lexpr to a vexpr.
680 ExprKind::Use { source: source.to_ref() }
682 ExprKind::Cast { source: source.to_ref() }
685 hir::ExprType(ref source, _) => return source.make_mirror(cx),
686 hir::ExprBox(ref value) => {
688 value: value.to_ref(),
689 value_extents: cx.tcx.region_maps.node_extent(value.id),
692 hir::ExprArray(ref fields) => ExprKind::Array { fields: fields.to_ref() },
693 hir::ExprTup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() },
697 temp_lifetime: temp_lifetime,
698 temp_lifetime_was_shrunk: was_shrunk,
705 fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
707 method_call: ty::MethodCall)
709 let callee = cx.tables().method_map[&method_call];
710 let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id);
712 temp_lifetime: temp_lifetime,
713 temp_lifetime_was_shrunk: was_shrunk,
716 kind: ExprKind::Literal {
717 literal: Literal::Value {
718 value: ConstVal::Function(callee.def_id, callee.substs),
724 fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
726 hir::MutMutable => BorrowKind::Mut,
727 hir::MutImmutable => BorrowKind::Shared,
731 fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
733 patterns: arm.pats.iter().map(|p| Pattern::from_hir(cx.tcx, cx.tables(), p)).collect(),
734 guard: arm.guard.to_ref(),
735 body: arm.body.to_ref(),
739 fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
740 expr: &'tcx hir::Expr,
743 let substs = cx.tables().node_id_item_substs(expr.id)
744 .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
746 // A regular function, constructor function or a constant.
748 Def::Method(def_id) |
749 Def::StructCtor(def_id, CtorKind::Fn) |
750 Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal {
751 literal: Literal::Value {
752 value: ConstVal::Function(def_id, substs),
757 Def::AssociatedConst(def_id) => ExprKind::Literal {
758 literal: Literal::Item {
764 Def::StructCtor(def_id, CtorKind::Const) |
765 Def::VariantCtor(def_id, CtorKind::Const) => {
766 match cx.tables().node_id_to_type(expr.id).sty {
767 // A unit struct/variant which is used as a value.
768 // We return a completely different ExprKind here to account for this special case.
769 ty::TyAdt(adt_def, substs) => {
772 variant_index: adt_def.variant_index_with_id(def_id),
778 ref sty => bug!("unexpected sty: {:?}", sty),
782 Def::Static(node_id, _) => ExprKind::StaticRef { id: node_id },
784 Def::Local(..) | Def::Upvar(..) => convert_var(cx, expr, def),
786 _ => span_bug!(expr.span, "def `{:?}` not yet implemented", def),
790 fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
791 expr: &'tcx hir::Expr,
794 let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id);
797 Def::Local(def_id) => {
798 let node_id = cx.tcx.hir.as_local_node_id(def_id).unwrap();
799 ExprKind::VarRef { id: node_id }
802 Def::Upvar(def_id, index, closure_expr_id) => {
803 let id_var = cx.tcx.hir.as_local_node_id(def_id).unwrap();
804 debug!("convert_var(upvar({:?}, {:?}, {:?}))",
808 let var_ty = cx.tables().node_id_to_type(id_var);
810 let body_id = match cx.tcx.hir.find(closure_expr_id) {
811 Some(map::NodeExpr(expr)) => {
813 hir::ExprClosure(.., body, _) => body.node_id,
815 span_bug!(expr.span, "closure expr is not a closure expr");
820 span_bug!(expr.span, "ast-map has garbage for closure expr");
824 // FIXME free regions in closures are not right
825 let closure_ty = cx.tables().node_id_to_type(closure_expr_id);
827 // FIXME we're just hard-coding the idea that the
828 // signature will be &self or &mut self and hence will
829 // have a bound region with number 0
830 let region = ty::Region::ReFree(ty::FreeRegion {
831 scope: cx.tcx.region_maps.node_extent(body_id),
832 bound_region: ty::BoundRegion::BrAnon(0),
834 let region = cx.tcx.mk_region(region);
836 let self_expr = match cx.tcx.closure_kind(cx.tcx.hir.local_def_id(closure_expr_id)) {
837 ty::ClosureKind::Fn => {
838 let ref_closure_ty = cx.tcx.mk_ref(region,
841 mutbl: hir::MutImmutable,
845 temp_lifetime: temp_lifetime,
846 temp_lifetime_was_shrunk: was_shrunk,
848 kind: ExprKind::Deref {
851 temp_lifetime: temp_lifetime,
852 temp_lifetime_was_shrunk: was_shrunk,
854 kind: ExprKind::SelfRef,
860 ty::ClosureKind::FnMut => {
861 let ref_closure_ty = cx.tcx.mk_ref(region,
864 mutbl: hir::MutMutable,
868 temp_lifetime: temp_lifetime,
869 temp_lifetime_was_shrunk: was_shrunk,
871 kind: ExprKind::Deref {
874 temp_lifetime: temp_lifetime,
875 temp_lifetime_was_shrunk: was_shrunk,
877 kind: ExprKind::SelfRef,
882 ty::ClosureKind::FnOnce => {
885 temp_lifetime: temp_lifetime,
886 temp_lifetime_was_shrunk: was_shrunk,
888 kind: ExprKind::SelfRef,
893 // at this point we have `self.n`, which loads up the upvar
894 let field_kind = ExprKind::Field {
895 lhs: self_expr.to_ref(),
896 name: Field::new(index),
899 // ...but the upvar might be an `&T` or `&mut T` capture, at which
900 // point we need an implicit deref
901 let upvar_id = ty::UpvarId {
903 closure_expr_id: closure_expr_id,
905 let upvar_capture = match cx.tables().upvar_capture(upvar_id) {
908 span_bug!(expr.span, "no upvar_capture for {:?}", upvar_id);
911 match upvar_capture {
912 ty::UpvarCapture::ByValue => field_kind,
913 ty::UpvarCapture::ByRef(borrow) => {
916 temp_lifetime: temp_lifetime,
917 temp_lifetime_was_shrunk: was_shrunk,
918 ty: cx.tcx.mk_ref(borrow.region,
921 mutbl: borrow.kind.to_mutbl_lossy(),
931 _ => span_bug!(expr.span, "type of & not region"),
936 fn bin_op(op: hir::BinOp_) -> BinOp {
938 hir::BinOp_::BiAdd => BinOp::Add,
939 hir::BinOp_::BiSub => BinOp::Sub,
940 hir::BinOp_::BiMul => BinOp::Mul,
941 hir::BinOp_::BiDiv => BinOp::Div,
942 hir::BinOp_::BiRem => BinOp::Rem,
943 hir::BinOp_::BiBitXor => BinOp::BitXor,
944 hir::BinOp_::BiBitAnd => BinOp::BitAnd,
945 hir::BinOp_::BiBitOr => BinOp::BitOr,
946 hir::BinOp_::BiShl => BinOp::Shl,
947 hir::BinOp_::BiShr => BinOp::Shr,
948 hir::BinOp_::BiEq => BinOp::Eq,
949 hir::BinOp_::BiLt => BinOp::Lt,
950 hir::BinOp_::BiLe => BinOp::Le,
951 hir::BinOp_::BiNe => BinOp::Ne,
952 hir::BinOp_::BiGe => BinOp::Ge,
953 hir::BinOp_::BiGt => BinOp::Gt,
954 _ => bug!("no equivalent for ast binop {:?}", op),
963 fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
964 expr: &'tcx hir::Expr,
965 method_call: ty::MethodCall,
967 receiver: ExprRef<'tcx>,
968 args: Vec<&'tcx P<hir::Expr>>)
970 // the receiver has all the adjustments that are needed, so we can
971 // just push a reference to it
972 let mut argrefs = vec![receiver];
974 // the arguments, unfortunately, do not, so if this is a ByRef
975 // operator, we have to gin up the autorefs (but by value is easy)
977 PassArgs::ByValue => argrefs.extend(args.iter().map(|arg| arg.to_ref())),
980 let region = cx.tcx.node_scope_region(expr.id);
981 let (temp_lifetime, was_shrunk) =
982 cx.tcx.region_maps.temporary_scope2(expr.id);
983 argrefs.extend(args.iter()
985 let arg_ty = cx.tables().expr_ty_adjusted(arg);
986 let adjusted_ty = cx.tcx.mk_ref(region,
989 mutbl: hir::MutImmutable,
992 temp_lifetime: temp_lifetime,
993 temp_lifetime_was_shrunk: was_shrunk,
996 kind: ExprKind::Borrow {
998 borrow_kind: BorrowKind::Shared,
1007 // now create the call itself
1008 let fun = method_callee(cx, expr, method_call);
1016 fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
1017 expr: &'tcx hir::Expr,
1018 method_call: ty::MethodCall,
1019 pass_args: PassArgs,
1020 receiver: ExprRef<'tcx>,
1021 args: Vec<&'tcx P<hir::Expr>>)
1023 // For an overloaded *x or x[y] expression of type T, the method
1024 // call returns an &T and we must add the deref so that the types
1025 // line up (this is because `*x` and `x[y]` represent lvalues):
1027 // to find the type &T of the content returned by the method;
1028 let ref_ty = cx.tables().method_map[&method_call].ty.fn_ret();
1029 let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap();
1030 // callees always have all late-bound regions fully instantiated,
1032 // construct the complete expression `foo()` for the overloaded call,
1033 // which will yield the &T type
1034 let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(expr.id);
1035 let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
1036 let ref_expr = Expr {
1037 temp_lifetime: temp_lifetime,
1038 temp_lifetime_was_shrunk: was_shrunk,
1044 // construct and return a deref wrapper `*foo()`
1045 ExprKind::Deref { arg: ref_expr.to_ref() }
1048 fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
1049 closure_expr: &'tcx hir::Expr,
1050 freevar: &hir::Freevar,
1051 freevar_ty: Ty<'tcx>)
1053 let id_var = cx.tcx.hir.as_local_node_id(freevar.def.def_id()).unwrap();
1054 let upvar_id = ty::UpvarId {
1056 closure_expr_id: closure_expr.id,
1058 let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap();
1059 let (temp_lifetime, was_shrunk) = cx.tcx.region_maps.temporary_scope2(closure_expr.id);
1060 let var_ty = cx.tables().node_id_to_type(id_var);
1061 let captured_var = Expr {
1062 temp_lifetime: temp_lifetime,
1063 temp_lifetime_was_shrunk: was_shrunk,
1065 span: closure_expr.span,
1066 kind: convert_var(cx, closure_expr, freevar.def),
1068 match upvar_capture {
1069 ty::UpvarCapture::ByValue => captured_var.to_ref(),
1070 ty::UpvarCapture::ByRef(upvar_borrow) => {
1071 let borrow_kind = match upvar_borrow.kind {
1072 ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
1073 ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
1074 ty::BorrowKind::MutBorrow => BorrowKind::Mut,
1077 temp_lifetime: temp_lifetime,
1078 temp_lifetime_was_shrunk: was_shrunk,
1080 span: closure_expr.span,
1081 kind: ExprKind::Borrow {
1082 region: upvar_borrow.region,
1083 borrow_kind: borrow_kind,
1084 arg: captured_var.to_ref(),
1091 /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef.
1092 fn field_refs<'tcx>(variant: &'tcx VariantDef,
1093 fields: &'tcx [hir::Field])
1094 -> Vec<FieldExprRef<'tcx>> {
1098 name: Field::new(variant.index_of_field_named(field.name.node).unwrap()),
1099 expr: field.expr.to_ref(),