]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_mir/hair/cx/expr.rs
New upstream version 1.22.1+dfsg1
[rustc.git] / src / librustc_mir / hair / cx / expr.rs
index ba0d3b49a6c1ae28315fd51bd8085db29f982470..f5a53e2aa8eed92a11cff1df9e2298533160f4fa 100644 (file)
@@ -14,223 +14,174 @@ use rustc_const_math::ConstInt;
 use hair::cx::Cx;
 use hair::cx::block;
 use hair::cx::to_ref::ToRef;
-use rustc::hir::map;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
-use rustc_const_eval as const_eval;
-use rustc::middle::region::CodeExtent;
 use rustc::ty::{self, AdtKind, VariantDef, Ty};
+use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::ty::cast::CastKind as TyCastKind;
-use rustc::mir::*;
 use rustc::hir;
-use syntax::ptr::P;
 
 impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     type Output = Expr<'tcx>;
 
     fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
-        let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id);
-        let expr_extent = cx.tcx.region_maps.node_extent(self.id);
+        let temp_lifetime = cx.region_scope_tree.temporary_scope(self.hir_id.local_id);
+        let expr_scope = region::Scope::Node(self.hir_id.local_id);
 
         debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
 
         let mut expr = make_mirror_unadjusted(cx, self);
-        let adj = cx.tcx.tables().adjustments.get(&self.id).cloned();
-
-        debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
-               expr, adj);
 
         // Now apply adjustments, if any.
-        match adj.map(|adj| (adj.kind, adj.target)) {
-            None => {}
-            Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => {
-                expr = Expr {
-                    temp_lifetime: temp_lifetime,
-                    ty: adjusted_ty,
-                    span: self.span,
-                    kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
-                };
-            }
-            Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => {
-                expr = Expr {
-                    temp_lifetime: temp_lifetime,
-                    ty: adjusted_ty,
-                    span: self.span,
-                    kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
-                };
-            }
-            Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
-                expr = Expr {
-                    temp_lifetime: temp_lifetime,
-                    ty: adjusted_ty,
-                    span: self.span,
-                    kind: ExprKind::NeverToAny { source: expr.to_ref() },
-                };
-            }
-            Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => {
-                expr = Expr {
-                    temp_lifetime: temp_lifetime,
-                    ty: adjusted_ty,
-                    span: self.span,
-                    kind: ExprKind::Cast { source: expr.to_ref() },
-                };
-            }
-            Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize },
-                  adjusted_ty)) => {
-                for i in 0..autoderefs {
-                    let i = i as u32;
-                    let adjusted_ty =
-                        expr.ty.adjust_for_autoderef(
-                            cx.tcx,
-                            self.id,
-                            self.span,
-                            i,
-                            |mc| cx.tcx.tables().method_map.get(&mc).map(|m| m.ty));
-                    debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", i, adjusted_ty);
-                    let method_key = ty::MethodCall::autoderef(self.id, i);
-                    let meth_ty =
-                        cx.tcx.tables().method_map.get(&method_key).map(|m| m.ty);
-                    let kind = if let Some(meth_ty) = meth_ty {
-                        debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
-
-                        let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
-                        let (region, mutbl) = match ref_ty {
-                            Some(&ty::TyS {
-                                sty: ty::TyRef(region, mt), ..
-                            }) => (region, mt.mutbl),
-                            _ => span_bug!(expr.span, "autoderef returned bad type")
-                        };
-
-                        expr = Expr {
-                            temp_lifetime: temp_lifetime,
-                            ty: cx.tcx.mk_ref(
-                                region, ty::TypeAndMut { ty: expr.ty, mutbl: mutbl }),
-                            span: expr.span,
-                            kind: ExprKind::Borrow {
-                                region: region,
-                                borrow_kind: to_borrow_kind(mutbl),
-                                arg: expr.to_ref()
-                            }
-                        };
-
-                        overloaded_lvalue(cx, self, method_key,
-                                          PassArgs::ByRef, expr.to_ref(), vec![])
-                    } else {
-                        debug!("make_mirror: built-in autoderef");
-                        ExprKind::Deref { arg: expr.to_ref() }
-                    };
-                    expr = Expr {
-                        temp_lifetime: temp_lifetime,
-                        ty: adjusted_ty,
-                        span: self.span,
-                        kind: kind,
-                    };
-                }
-
-                if let Some(autoref) = autoref {
-                    let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
-                    match autoref {
-                        ty::adjustment::AutoBorrow::Ref(r, m) => {
-                            expr = Expr {
-                                temp_lifetime: temp_lifetime,
-                                ty: adjusted_ty,
-                                span: self.span,
-                                kind: ExprKind::Borrow {
-                                    region: r,
-                                    borrow_kind: to_borrow_kind(m),
-                                    arg: expr.to_ref(),
-                                },
-                            };
-                        }
-                        ty::adjustment::AutoBorrow::RawPtr(m) => {
-                            // Convert this to a suitable `&foo` and
-                            // then an unsafe coercion. Limit the region to be just this
-                            // expression.
-                            let region = ty::ReScope(expr_extent);
-                            let region = cx.tcx.mk_region(region);
-                            expr = Expr {
-                                temp_lifetime: temp_lifetime,
-                                ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, mutbl: m }),
-                                span: self.span,
-                                kind: ExprKind::Borrow {
-                                    region: region,
-                                    borrow_kind: to_borrow_kind(m),
-                                    arg: expr.to_ref(),
-                                },
-                            };
-                            expr = Expr {
-                                temp_lifetime: temp_lifetime,
-                                ty: adjusted_ty,
-                                span: self.span,
-                                kind: ExprKind::Cast { source: expr.to_ref() },
-                            };
-                        }
-                    }
-                }
-
-                if unsize {
-                    expr = Expr {
-                        temp_lifetime: temp_lifetime,
-                        ty: adjusted_ty,
-                        span: self.span,
-                        kind: ExprKind::Unsize { source: expr.to_ref() },
-                    };
-                }
-            }
+        for adjustment in cx.tables().expr_adjustments(self) {
+            debug!("make_mirror: expr={:?} applying adjustment={:?}",
+                   expr,
+                   adjustment);
+            expr = apply_adjustment(cx, self, expr, adjustment);
         }
 
         // Next, wrap this up in the expr's scope.
         expr = Expr {
-            temp_lifetime: temp_lifetime,
+            temp_lifetime,
             ty: expr.ty,
             span: self.span,
             kind: ExprKind::Scope {
-                extent: expr_extent,
+                region_scope: expr_scope,
                 value: expr.to_ref(),
+                lint_level: cx.lint_level_of(self.id),
             },
         };
 
         // Finally, create a destruction scope, if any.
-        if let Some(extent) = cx.tcx.region_maps.opt_destruction_extent(self.id) {
+        if let Some(region_scope) =
+            cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id) {
+                expr = Expr {
+                    temp_lifetime,
+                    ty: expr.ty,
+                    span: self.span,
+                    kind: ExprKind::Scope {
+                        region_scope,
+                        value: expr.to_ref(),
+                        lint_level: LintLevel::Inherited,
+                    },
+                };
+            }
+
+        // OK, all done!
+        expr
+    }
+}
+
+fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                                    hir_expr: &'tcx hir::Expr,
+                                    mut expr: Expr<'tcx>,
+                                    adjustment: &Adjustment<'tcx>)
+                                    -> Expr<'tcx> {
+    let Expr { temp_lifetime, span, .. } = expr;
+    let kind = match adjustment.kind {
+        Adjust::ReifyFnPointer => {
+            ExprKind::ReifyFnPointer { source: expr.to_ref() }
+        }
+        Adjust::UnsafeFnPointer => {
+            ExprKind::UnsafeFnPointer { source: expr.to_ref() }
+        }
+        Adjust::ClosureFnPointer => {
+            ExprKind::ClosureFnPointer { source: expr.to_ref() }
+        }
+        Adjust::NeverToAny => {
+            ExprKind::NeverToAny { source: expr.to_ref() }
+        }
+        Adjust::MutToConstPointer => {
+            ExprKind::Cast { source: expr.to_ref() }
+        }
+        Adjust::Deref(None) => {
+            ExprKind::Deref { arg: expr.to_ref() }
+        }
+        Adjust::Deref(Some(deref)) => {
+            let call = deref.method_call(cx.tcx, expr.ty);
+
             expr = Expr {
-                temp_lifetime: temp_lifetime,
-                ty: expr.ty,
-                span: self.span,
-                kind: ExprKind::Scope {
-                    extent: extent,
-                    value: expr.to_ref(),
+                temp_lifetime,
+                ty: cx.tcx.mk_ref(deref.region,
+                                  ty::TypeAndMut {
+                                    ty: expr.ty,
+                                    mutbl: deref.mutbl,
+                                  }),
+                span,
+                kind: ExprKind::Borrow {
+                    region: deref.region,
+                    borrow_kind: to_borrow_kind(deref.mutbl),
+                    arg: expr.to_ref(),
                 },
             };
+
+            overloaded_lvalue(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
+        }
+        Adjust::Borrow(AutoBorrow::Ref(r, m)) => {
+            ExprKind::Borrow {
+                region: r,
+                borrow_kind: to_borrow_kind(m),
+                arg: expr.to_ref(),
+            }
         }
+        Adjust::Borrow(AutoBorrow::RawPtr(m)) => {
+            // Convert this to a suitable `&foo` and
+            // then an unsafe coercion. Limit the region to be just this
+            // expression.
+            let region = ty::ReScope(region::Scope::Node(hir_expr.hir_id.local_id));
+            let region = cx.tcx.mk_region(region);
+            expr = Expr {
+                temp_lifetime,
+                ty: cx.tcx.mk_ref(region,
+                                  ty::TypeAndMut {
+                                    ty: expr.ty,
+                                    mutbl: m,
+                                  }),
+                span,
+                kind: ExprKind::Borrow {
+                    region,
+                    borrow_kind: to_borrow_kind(m),
+                    arg: expr.to_ref(),
+                },
+            };
+            ExprKind::Cast { source: expr.to_ref() }
+        }
+        Adjust::Unsize => {
+            ExprKind::Unsize { source: expr.to_ref() }
+        }
+    };
 
-        // OK, all done!
-        expr
+    Expr {
+        temp_lifetime,
+        ty: adjustment.target,
+        span,
+        kind,
     }
 }
 
 fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                           expr: &'tcx hir::Expr)
                                           -> Expr<'tcx> {
-    let expr_ty = cx.tcx.tables().expr_ty(expr);
-    let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
+    let expr_ty = cx.tables().expr_ty(expr);
+    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
 
     let kind = match expr.node {
         // Here comes the interesting stuff:
         hir::ExprMethodCall(.., ref args) => {
             // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
-            let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
+            let expr = method_callee(cx, expr, None);
             let args = args.iter()
                 .map(|e| e.to_ref())
                 .collect();
             ExprKind::Call {
                 ty: expr.ty,
                 fun: expr.to_ref(),
-                args: args,
+                args,
             }
         }
 
         hir::ExprCall(ref fun, ref args) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
+            if cx.tables().is_method_call(expr) {
                 // The callee is something implementing Fn, FnMut, or FnOnce.
                 // Find the actual method implementation being called and
                 // build the appropriate UFCS call expression with the
@@ -238,65 +189,57 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
                 // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
 
-                let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
-
-                let sig = match method.ty.sty {
-                    ty::TyFnDef(.., fn_ty) => &fn_ty.sig,
-                    _ => span_bug!(expr.span, "type of method is not an fn")
-                };
-
-                let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| {
-                    span_bug!(expr.span, "method call has late-bound regions")
-                });
-
-                assert_eq!(sig.inputs.len(), 2);
+                let method = method_callee(cx, expr, None);
 
+                let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
                 let tupled_args = Expr {
-                    ty: sig.inputs[1],
-                    temp_lifetime: temp_lifetime,
+                    ty: cx.tcx.mk_tup(arg_tys, false),
+                    temp_lifetime,
                     span: expr.span,
-                    kind: ExprKind::Tuple {
-                        fields: args.iter().map(ToRef::to_ref).collect()
-                    }
+                    kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() },
                 };
 
                 ExprKind::Call {
                     ty: method.ty,
                     fun: method.to_ref(),
-                    args: vec![fun.to_ref(), tupled_args.to_ref()]
+                    args: vec![fun.to_ref(), tupled_args.to_ref()],
                 }
             } else {
-                let adt_data = if let hir::ExprPath(..) = fun.node {
+                let adt_data = if let hir::ExprPath(hir::QPath::Resolved(_, ref path)) = fun.node {
                     // Tuple-like ADTs are represented as ExprCall. We convert them here.
-                    expr_ty.ty_adt_def().and_then(|adt_def|{
-                        match cx.tcx.expect_def(fun.id) {
+                    expr_ty.ty_adt_def().and_then(|adt_def| {
+                        match path.def {
                             Def::VariantCtor(variant_id, CtorKind::Fn) => {
                                 Some((adt_def, adt_def.variant_index_with_id(variant_id)))
-                            },
-                            Def::StructCtor(_, CtorKind::Fn) => {
-                                Some((adt_def, 0))
-                            },
-                            _ => None
+                            }
+                            Def::StructCtor(_, CtorKind::Fn) => Some((adt_def, 0)),
+                            _ => None,
                         }
                     })
-                } else { None };
+                } else {
+                    None
+                };
                 if let Some((adt_def, index)) = adt_data {
-                    let substs = cx.tcx.tables().node_id_item_substs(fun.id)
-                        .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
-                    let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef {
-                        name: Field::new(idx),
-                        expr: e.to_ref()
-                    }).collect();
+                    let substs = cx.tables().node_substs(fun.hir_id);
+                    let field_refs = args.iter()
+                        .enumerate()
+                        .map(|(idx, e)| {
+                            FieldExprRef {
+                                name: Field::new(idx),
+                                expr: e.to_ref(),
+                            }
+                        })
+                        .collect();
                     ExprKind::Adt {
-                        adt_def: adt_def,
-                        substs: substs,
+                        adt_def,
+                        substs,
                         variant_index: index,
                         fields: field_refs,
-                        base: None
+                        base: None,
                     }
                 } else {
                     ExprKind::Call {
-                        ty: cx.tcx.tables().node_id_to_type(fun.id),
+                        ty: cx.tables().node_id_to_type(fun.hir_id),
                         fun: fun.to_ref(),
                         args: args.to_ref(),
                     }
@@ -310,15 +253,13 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 _ => span_bug!(expr.span, "type of & not region"),
             };
             ExprKind::Borrow {
-                region: region,
+                region,
                 borrow_kind: to_borrow_kind(mutbl),
                 arg: expr.to_ref(),
             }
         }
 
-        hir::ExprBlock(ref blk) => {
-            ExprKind::Block { body: &blk }
-        }
+        hir::ExprBlock(ref blk) => ExprKind::Block { body: &blk },
 
         hir::ExprAssign(ref lhs, ref rhs) => {
             ExprKind::Assign {
@@ -328,14 +269,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
-                let pass_args = if op.node.is_by_value() {
-                    PassArgs::ByValue
-                } else {
-                    PassArgs::ByRef
-                };
-                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
-                                    pass_args, lhs.to_ref(), vec![rhs])
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
             } else {
                 ExprKind::AssignOp {
                     op: bin_op(op.node),
@@ -345,19 +280,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             }
         }
 
-        hir::ExprLit(..) => ExprKind::Literal {
-            literal: cx.const_eval_literal(expr)
-        },
+        hir::ExprLit(..) => ExprKind::Literal { literal: cx.const_eval_literal(expr) },
 
         hir::ExprBinary(op, ref lhs, ref rhs) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
-                let pass_args = if op.node.is_by_value() {
-                    PassArgs::ByValue
-                } else {
-                    PassArgs::ByRef
-                };
-                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
-                                    pass_args, lhs.to_ref(), vec![rhs])
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
             } else {
                 // FIXME overflow
                 match (op.node, cx.constness) {
@@ -396,7 +323,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     _ => {
                         let op = bin_op(op.node);
                         ExprKind::Binary {
-                            op: op,
+                            op,
                             lhs: lhs.to_ref(),
                             rhs: rhs.to_ref(),
                         }
@@ -406,9 +333,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprIndex(ref lhs, ref index) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
-                overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id),
-                                  PassArgs::ByValue, lhs.to_ref(), vec![index])
+            if cx.tables().is_method_call(expr) {
+                overloaded_lvalue(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()])
             } else {
                 ExprKind::Index {
                     lhs: lhs.to_ref(),
@@ -418,18 +344,16 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
-                overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id),
-                                  PassArgs::ByValue, arg.to_ref(), vec![])
+            if cx.tables().is_method_call(expr) {
+                overloaded_lvalue(cx, expr, expr_ty, None, vec![arg.to_ref()])
             } else {
                 ExprKind::Deref { arg: arg.to_ref() }
             }
         }
 
         hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
-                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
-                                    PassArgs::ByValue, arg.to_ref(), vec![])
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![arg.to_ref()])
             } else {
                 ExprKind::Unary {
                     op: UnOp::Not,
@@ -439,15 +363,12 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
-            if cx.tcx.tables().is_method_call(expr.id) {
-                overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id),
-                                    PassArgs::ByValue, arg.to_ref(), vec![])
+            if cx.tables().is_method_call(expr) {
+                overloaded_operator(cx, expr, vec![arg.to_ref()])
             } else {
                 // FIXME runtime-overflow
                 if let hir::ExprLit(_) = arg.node {
-                    ExprKind::Literal {
-                        literal: cx.const_eval_literal(expr),
-                    }
+                    ExprKind::Literal { literal: cx.const_eval_literal(expr) }
                 } else {
                     ExprKind::Unary {
                         op: UnOp::Neg,
@@ -457,188 +378,232 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             }
         }
 
-        hir::ExprStruct(_, ref fields, ref base) => {
+        hir::ExprStruct(ref qpath, ref fields, ref base) => {
             match expr_ty.sty {
-                ty::TyAdt(adt, substs) => match adt.adt_kind() {
-                    AdtKind::Struct | AdtKind::Union => {
-                        let field_refs = field_refs(&adt.variants[0], fields);
-                        ExprKind::Adt {
-                            adt_def: adt,
-                            variant_index: 0,
-                            substs: substs,
-                            fields: field_refs,
-                            base: base.as_ref().map(|base| {
-                                FruInfo {
-                                    base: base.to_ref(),
-                                    field_types:
-                                        cx.tcx.tables().fru_field_types[&expr.id].clone()
-                                }
-                            })
+                ty::TyAdt(adt, substs) => {
+                    match adt.adt_kind() {
+                        AdtKind::Struct | AdtKind::Union => {
+                            let field_refs = field_refs(&adt.variants[0], fields);
+                            ExprKind::Adt {
+                                adt_def: adt,
+                                variant_index: 0,
+                                substs,
+                                fields: field_refs,
+                                base: base.as_ref().map(|base| {
+                                    FruInfo {
+                                        base: base.to_ref(),
+                                        field_types: cx.tables()
+                                                       .fru_field_types()[expr.hir_id]
+                                                       .clone(),
+                                    }
+                                }),
+                            }
                         }
-                    }
-                    AdtKind::Enum => {
-                        match cx.tcx.expect_def(expr.id) {
-                            Def::Variant(variant_id) => {
-                                assert!(base.is_none());
-
-                                let index = adt.variant_index_with_id(variant_id);
-                                let field_refs = field_refs(&adt.variants[index], fields);
-                                ExprKind::Adt {
-                                    adt_def: adt,
-                                    variant_index: index,
-                                    substs: substs,
-                                    fields: field_refs,
-                                    base: None
+                        AdtKind::Enum => {
+                            let def = match *qpath {
+                                hir::QPath::Resolved(_, ref path) => path.def,
+                                hir::QPath::TypeRelative(..) => Def::Err,
+                            };
+                            match def {
+                                Def::Variant(variant_id) => {
+                                    assert!(base.is_none());
+
+                                    let index = adt.variant_index_with_id(variant_id);
+                                    let field_refs = field_refs(&adt.variants[index], fields);
+                                    ExprKind::Adt {
+                                        adt_def: adt,
+                                        variant_index: index,
+                                        substs,
+                                        fields: field_refs,
+                                        base: None,
+                                    }
+                                }
+                                _ => {
+                                    span_bug!(expr.span, "unexpected def: {:?}", def);
                                 }
-                            }
-                            ref def => {
-                                span_bug!(
-                                    expr.span,
-                                    "unexpected def: {:?}",
-                                    def);
                             }
                         }
                     }
-                },
+                }
                 _ => {
-                    span_bug!(
-                        expr.span,
-                        "unexpected type for struct literal: {:?}",
-                        expr_ty);
+                    span_bug!(expr.span,
+                              "unexpected type for struct literal: {:?}",
+                              expr_ty);
                 }
             }
         }
 
         hir::ExprClosure(..) => {
-            let closure_ty = cx.tcx.tables().expr_ty(expr);
-            let (def_id, substs) = match closure_ty.sty {
-                ty::TyClosure(def_id, substs) => (def_id, substs),
+            let closure_ty = cx.tables().expr_ty(expr);
+            let (def_id, substs, interior) = match closure_ty.sty {
+                ty::TyClosure(def_id, substs) => (def_id, substs, None),
+                ty::TyGenerator(def_id, substs, interior) => (def_id, substs, Some(interior)),
                 _ => {
-                    span_bug!(expr.span,
-                              "closure expr w/o closure type: {:?}",
-                              closure_ty);
+                    span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
                 }
             };
             let upvars = cx.tcx.with_freevars(expr.id, |freevars| {
                 freevars.iter()
-                    .enumerate()
-                    .map(|(i, fv)| capture_freevar(cx, expr, fv, substs.upvar_tys[i]))
+                    .zip(substs.upvar_tys(def_id, cx.tcx))
+                    .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty))
                     .collect()
             });
             ExprKind::Closure {
                 closure_id: def_id,
-                substs: substs,
-                upvars: upvars,
+                substs,
+                upvars,
+                interior,
             }
         }
 
-        hir::ExprPath(..) => {
-            convert_path_expr(cx, expr)
+        hir::ExprPath(ref qpath) => {
+            let def = cx.tables().qpath_def(qpath, expr.hir_id);
+            convert_path_expr(cx, expr, def)
         }
 
         hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => {
             ExprKind::InlineAsm {
-                asm: asm,
+                asm,
                 outputs: outputs.to_ref(),
-                inputs: inputs.to_ref()
+                inputs: inputs.to_ref(),
             }
         }
 
         // Now comes the rote stuff:
+        hir::ExprRepeat(ref v, count) => {
+            let c = &cx.tcx.hir.body(count).value;
+            let def_id = cx.tcx.hir.body_owner_def_id(count);
+            let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
+            let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) {
+                Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u,
+                Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
+                Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
+            };
 
-        hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat {
-            value: v.to_ref(),
-            count: TypedConstVal {
-                ty: cx.tcx.tables().expr_ty(c),
-                span: c.span,
-                value: match const_eval::eval_const_expr(cx.tcx.global_tcx(), c) {
-                    ConstVal::Integral(ConstInt::Usize(u)) => u,
-                    other => bug!("constant evaluation of repeat count yielded {:?}", other),
+            ExprKind::Repeat {
+                value: v.to_ref(),
+                count,
+            }
+        }
+        hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
+        hir::ExprBreak(dest, ref value) => {
+            match dest.target_id {
+                hir::ScopeTarget::Block(target_id) |
+                hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break {
+                    label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(target_id).local_id),
+                    value: value.to_ref(),
                 },
+                hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
+                    bug!("invalid loop id for break: {}", err)
             }
-        },
-        hir::ExprRet(ref v) =>
-            ExprKind::Return { value: v.to_ref() },
-        hir::ExprBreak(label) =>
-            ExprKind::Break { label: label.map(|_| loop_label(cx, expr)) },
-        hir::ExprAgain(label) =>
-            ExprKind::Continue { label: label.map(|_| loop_label(cx, expr)) },
-        hir::ExprMatch(ref discr, ref arms, _) =>
-            ExprKind::Match { discriminant: discr.to_ref(),
-                              arms: arms.iter().map(|a| convert_arm(cx, a)).collect() },
-        hir::ExprIf(ref cond, ref then, ref otherwise) =>
-            ExprKind::If { condition: cond.to_ref(),
-                           then: block::to_expr_ref(cx, then),
-                           otherwise: otherwise.to_ref() },
-        hir::ExprWhile(ref cond, ref body, _) =>
-            ExprKind::Loop { condition: Some(cond.to_ref()),
-                             body: block::to_expr_ref(cx, body) },
-        hir::ExprLoop(ref body, _) =>
-            ExprKind::Loop { condition: None,
-                             body: block::to_expr_ref(cx, body) },
+        }
+        hir::ExprAgain(dest) => {
+            match dest.target_id {
+                hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"),
+                hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue {
+                    label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(loop_id).local_id),
+                },
+                hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
+                    bug!("invalid loop id for continue: {}", err)
+            }
+        }
+        hir::ExprMatch(ref discr, ref arms, _) => {
+            ExprKind::Match {
+                discriminant: discr.to_ref(),
+                arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
+            }
+        }
+        hir::ExprIf(ref cond, ref then, ref otherwise) => {
+            ExprKind::If {
+                condition: cond.to_ref(),
+                then: then.to_ref(),
+                otherwise: otherwise.to_ref(),
+            }
+        }
+        hir::ExprWhile(ref cond, ref body, _) => {
+            ExprKind::Loop {
+                condition: Some(cond.to_ref()),
+                body: block::to_expr_ref(cx, body),
+            }
+        }
+        hir::ExprLoop(ref body, _, _) => {
+            ExprKind::Loop {
+                condition: None,
+                body: block::to_expr_ref(cx, body),
+            }
+        }
         hir::ExprField(ref source, name) => {
-            let index = match cx.tcx.tables().expr_ty_adjusted(source).sty {
-                ty::TyAdt(adt_def, _) =>
-                    adt_def.variants[0].index_of_field_named(name.node),
-                ref ty =>
-                    span_bug!(expr.span, "field of non-ADT: {:?}", ty),
+            let index = match cx.tables().expr_ty_adjusted(source).sty {
+                ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node),
+                ref ty => span_bug!(expr.span, "field of non-ADT: {:?}", ty),
             };
-            let index = index.unwrap_or_else(|| {
-                span_bug!(
-                    expr.span,
-                    "no index found for field `{}`",
-                    name.node)
-            });
-            ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) }
+            let index =
+                index.unwrap_or_else(|| {
+                    span_bug!(expr.span, "no index found for field `{}`", name.node)
+                });
+            ExprKind::Field {
+                lhs: source.to_ref(),
+                name: Field::new(index),
+            }
+        }
+        hir::ExprTupField(ref source, index) => {
+            ExprKind::Field {
+                lhs: source.to_ref(),
+                name: Field::new(index.node as usize),
+            }
         }
-        hir::ExprTupField(ref source, index) =>
-            ExprKind::Field { lhs: source.to_ref(),
-                              name: Field::new(index.node as usize) },
         hir::ExprCast(ref source, _) => {
             // Check to see if this cast is a "coercion cast", where the cast is actually done
             // using a coercion (or is a no-op).
-            if let Some(&TyCastKind::CoercionCast) = cx.tcx.cast_kinds.borrow().get(&source.id) {
+            if let Some(&TyCastKind::CoercionCast) = cx.tables()
+                                                       .cast_kinds()
+                                                       .get(source.hir_id) {
                 // Convert the lexpr to a vexpr.
                 ExprKind::Use { source: source.to_ref() }
             } else {
                 ExprKind::Cast { source: source.to_ref() }
             }
         }
-        hir::ExprType(ref source, _) =>
-            return source.make_mirror(cx),
-        hir::ExprBox(ref value) =>
+        hir::ExprType(ref source, _) => return source.make_mirror(cx),
+        hir::ExprBox(ref value) => {
             ExprKind::Box {
                 value: value.to_ref(),
-                value_extents: cx.tcx.region_maps.node_extent(value.id)
-            },
-        hir::ExprArray(ref fields) =>
-            ExprKind::Vec { fields: fields.to_ref() },
-        hir::ExprTup(ref fields) =>
-            ExprKind::Tuple { fields: fields.to_ref() },
+            }
+        }
+        hir::ExprArray(ref fields) => ExprKind::Array { fields: fields.to_ref() },
+        hir::ExprTup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() },
+
+        hir::ExprYield(ref v) => ExprKind::Yield { value: v.to_ref() },
     };
 
     Expr {
-        temp_lifetime: temp_lifetime,
+        temp_lifetime,
         ty: expr_ty,
         span: expr.span,
-        kind: kind,
+        kind,
     }
 }
 
 fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                  expr: &hir::Expr,
-                                 method_call: ty::MethodCall)
+                                 custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>)
                                  -> Expr<'tcx> {
-    let callee = cx.tcx.tables().method_map[&method_call];
-    let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
+    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+    let (def_id, substs) = custom_callee.unwrap_or_else(|| {
+        (cx.tables().type_dependent_defs()[expr.hir_id].def_id(),
+         cx.tables().node_substs(expr.hir_id))
+    });
+    let ty = cx.tcx().mk_fn_def(def_id, substs);
     Expr {
-        temp_lifetime: temp_lifetime,
-        ty: callee.ty,
+        temp_lifetime,
+        ty,
         span: expr.span,
         kind: ExprKind::Literal {
-            literal: Literal::Item {
-                def_id: callee.def_id,
-                substs: callee.substs,
+            literal: Literal::Value {
+                value: cx.tcx.mk_const(ty::Const {
+                    val: ConstVal::Function(def_id, substs),
+                    ty
+                }),
             },
         },
     }
@@ -651,54 +616,68 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
     }
 }
 
-fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
-                               arm: &'tcx hir::Arm) -> Arm<'tcx> {
+fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
     Arm {
-        patterns: arm.pats.iter().map(|p| Pattern::from_hir(cx.tcx, p)).collect(),
+        patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(),
         guard: arm.guard.to_ref(),
         body: arm.body.to_ref(),
+        // BUG: fix this
+        lint_level: LintLevel::Inherited,
     }
 }
 
 fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
-                                     expr: &'tcx hir::Expr)
+                                     expr: &'tcx hir::Expr,
+                                     def: Def)
                                      -> ExprKind<'tcx> {
-    let substs = cx.tcx.tables().node_id_item_substs(expr.id)
-        .unwrap_or_else(|| cx.tcx.intern_substs(&[]));
-    let def = cx.tcx.expect_def(expr.id);
-    let def_id = match def {
+    let substs = cx.tables().node_substs(expr.hir_id);
+    match def {
         // A regular function, constructor function or a constant.
-        Def::Fn(def_id) | Def::Method(def_id) |
+        Def::Fn(def_id) |
+        Def::Method(def_id) |
         Def::StructCtor(def_id, CtorKind::Fn) |
-        Def::VariantCtor(def_id, CtorKind::Fn) |
-        Def::Const(def_id) | Def::AssociatedConst(def_id) => def_id,
+        Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal {
+            literal: Literal::Value {
+                value: cx.tcx.mk_const(ty::Const {
+                    val: ConstVal::Function(def_id, substs),
+                    ty: cx.tables().node_id_to_type(expr.hir_id)
+                }),
+            },
+        },
+
+        Def::Const(def_id) |
+        Def::AssociatedConst(def_id) => ExprKind::Literal {
+            literal: Literal::Value {
+                value: cx.tcx.mk_const(ty::Const {
+                    val: ConstVal::Unevaluated(def_id, substs),
+                    ty: cx.tables().node_id_to_type(expr.hir_id)
+                }),
+            },
+        },
 
         Def::StructCtor(def_id, CtorKind::Const) |
         Def::VariantCtor(def_id, CtorKind::Const) => {
-            match cx.tcx.tables().node_id_to_type(expr.id).sty {
+            match cx.tables().node_id_to_type(expr.hir_id).sty {
                 // A unit struct/variant which is used as a value.
                 // We return a completely different ExprKind here to account for this special case.
-                ty::TyAdt(adt_def, substs) => return ExprKind::Adt {
-                    adt_def: adt_def,
-                    variant_index: adt_def.variant_index_with_id(def_id),
-                    substs: substs,
-                    fields: vec![],
-                    base: None,
-                },
-                ref sty => bug!("unexpected sty: {:?}", sty)
+                ty::TyAdt(adt_def, substs) => {
+                    ExprKind::Adt {
+                        adt_def,
+                        variant_index: adt_def.variant_index_with_id(def_id),
+                        substs,
+                        fields: vec![],
+                        base: None,
+                    }
+                }
+                ref sty => bug!("unexpected sty: {:?}", sty),
             }
         }
 
-        Def::Static(node_id, _) => return ExprKind::StaticRef {
-            id: node_id,
-        },
+        Def::Static(node_id, _) => ExprKind::StaticRef { id: node_id },
 
-        Def::Local(..) | Def::Upvar(..) => return convert_var(cx, expr, def),
+        Def::Local(..) | Def::Upvar(..) => convert_var(cx, expr, def),
 
         _ => span_bug!(expr.span, "def `{:?}` not yet implemented", def),
-    };
-    ExprKind::Literal {
-        literal: Literal::Item { def_id: def_id, substs: substs }
     }
 }
 
@@ -706,94 +685,92 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                expr: &'tcx hir::Expr,
                                def: Def)
                                -> ExprKind<'tcx> {
-    let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
+    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
 
     match def {
-        Def::Local(def_id) => {
-            let node_id = cx.tcx.map.as_local_node_id(def_id).unwrap();
-            ExprKind::VarRef {
-                id: node_id,
-            }
-        }
+        Def::Local(id) => ExprKind::VarRef { id },
 
-        Def::Upvar(def_id, index, closure_expr_id) => {
-            let id_var = cx.tcx.map.as_local_node_id(def_id).unwrap();
-            debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
-            let var_ty = cx.tcx.tables().node_id_to_type(id_var);
-
-            let body_id = match cx.tcx.map.find(closure_expr_id) {
-                Some(map::NodeExpr(expr)) => {
-                    match expr.node {
-                        hir::ExprClosure(.., ref body, _) => body.id,
-                        _ => {
-                            span_bug!(expr.span, "closure expr is not a closure expr");
-                        }
-                    }
-                }
-                _ => {
-                    span_bug!(expr.span, "ast-map has garbage for closure expr");
-                }
-            };
+        Def::Upvar(var_id, index, closure_expr_id) => {
+            debug!("convert_var(upvar({:?}, {:?}, {:?}))",
+                   var_id,
+                   index,
+                   closure_expr_id);
+            let var_hir_id = cx.tcx.hir.node_to_hir_id(var_id);
+            let var_ty = cx.tables().node_id_to_type(var_hir_id);
 
             // FIXME free regions in closures are not right
-            let closure_ty = cx.tcx.tables().node_id_to_type(closure_expr_id);
+            let closure_ty = cx.tables()
+                               .node_id_to_type(cx.tcx.hir.node_to_hir_id(closure_expr_id));
 
             // FIXME we're just hard-coding the idea that the
             // signature will be &self or &mut self and hence will
             // have a bound region with number 0
-            let region = ty::Region::ReFree(ty::FreeRegion {
-                scope: cx.tcx.region_maps.node_extent(body_id),
+            let closure_def_id = cx.tcx.hir.local_def_id(closure_expr_id);
+            let region = ty::ReFree(ty::FreeRegion {
+                scope: closure_def_id,
                 bound_region: ty::BoundRegion::BrAnon(0),
             });
             let region = cx.tcx.mk_region(region);
 
-            let self_expr = match cx.tcx.closure_kind(cx.tcx.map.local_def_id(closure_expr_id)) {
-                ty::ClosureKind::Fn => {
-                    let ref_closure_ty =
-                        cx.tcx.mk_ref(region,
-                                   ty::TypeAndMut { ty: closure_ty,
-                                                    mutbl: hir::MutImmutable });
-                    Expr {
-                        ty: closure_ty,
-                        temp_lifetime: temp_lifetime,
-                        span: expr.span,
-                        kind: ExprKind::Deref {
-                            arg: Expr {
-                                ty: ref_closure_ty,
-                                temp_lifetime: temp_lifetime,
-                                span: expr.span,
-                                kind: ExprKind::SelfRef
-                            }.to_ref()
+            let self_expr = if let ty::TyClosure(..) = closure_ty.sty {
+                match cx.tcx.closure_kind(closure_def_id) {
+                    ty::ClosureKind::Fn => {
+                        let ref_closure_ty = cx.tcx.mk_ref(region,
+                                                           ty::TypeAndMut {
+                                                               ty: closure_ty,
+                                                               mutbl: hir::MutImmutable,
+                                                           });
+                        Expr {
+                            ty: closure_ty,
+                            temp_lifetime: temp_lifetime,
+                            span: expr.span,
+                            kind: ExprKind::Deref {
+                                arg: Expr {
+                                    ty: ref_closure_ty,
+                                    temp_lifetime,
+                                    span: expr.span,
+                                    kind: ExprKind::SelfRef,
+                                }
+                                .to_ref(),
+                            },
                         }
                     }
-                }
-                ty::ClosureKind::FnMut => {
-                    let ref_closure_ty =
-                        cx.tcx.mk_ref(region,
-                                   ty::TypeAndMut { ty: closure_ty,
-                                                    mutbl: hir::MutMutable });
-                    Expr {
-                        ty: closure_ty,
-                        temp_lifetime: temp_lifetime,
-                        span: expr.span,
-                        kind: ExprKind::Deref {
-                            arg: Expr {
-                                ty: ref_closure_ty,
-                                temp_lifetime: temp_lifetime,
-                                span: expr.span,
-                                kind: ExprKind::SelfRef
-                            }.to_ref()
+                    ty::ClosureKind::FnMut => {
+                        let ref_closure_ty = cx.tcx.mk_ref(region,
+                                                           ty::TypeAndMut {
+                                                               ty: closure_ty,
+                                                               mutbl: hir::MutMutable,
+                                                           });
+                        Expr {
+                            ty: closure_ty,
+                            temp_lifetime,
+                            span: expr.span,
+                            kind: ExprKind::Deref {
+                                arg: Expr {
+                                    ty: ref_closure_ty,
+                                    temp_lifetime,
+                                    span: expr.span,
+                                    kind: ExprKind::SelfRef,
+                                }.to_ref(),
+                            },
                         }
                     }
-                }
-                ty::ClosureKind::FnOnce => {
-                    Expr {
-                        ty: closure_ty,
-                        temp_lifetime: temp_lifetime,
-                        span: expr.span,
-                        kind: ExprKind::SelfRef,
+                    ty::ClosureKind::FnOnce => {
+                        Expr {
+                            ty: closure_ty,
+                            temp_lifetime,
+                            span: expr.span,
+                            kind: ExprKind::SelfRef,
+                        }
                     }
                 }
+            } else {
+                Expr {
+                    ty: closure_ty,
+                    temp_lifetime,
+                    span: expr.span,
+                    kind: ExprKind::SelfRef,
+                }
             };
 
             // at this point we have `self.n`, which loads up the upvar
@@ -805,32 +782,23 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             // ...but the upvar might be an `&T` or `&mut T` capture, at which
             // point we need an implicit deref
             let upvar_id = ty::UpvarId {
-                var_id: id_var,
-                closure_expr_id: closure_expr_id,
+                var_id: var_hir_id,
+                closure_expr_id: closure_def_id.index,
             };
-            let upvar_capture = match cx.tcx.tables().upvar_capture(upvar_id) {
-                Some(c) => c,
-                None => {
-                    span_bug!(
-                        expr.span,
-                        "no upvar_capture for {:?}",
-                        upvar_id);
-                }
-            };
-            match upvar_capture {
+            match cx.tables().upvar_capture(upvar_id) {
                 ty::UpvarCapture::ByValue => field_kind,
                 ty::UpvarCapture::ByRef(borrow) => {
                     ExprKind::Deref {
                         arg: Expr {
-                            temp_lifetime: temp_lifetime,
+                            temp_lifetime,
                             ty: cx.tcx.mk_ref(borrow.region,
-                                ty::TypeAndMut {
-                                    ty: var_ty,
-                                    mutbl: borrow.kind.to_mutbl_lossy()
-                                }),
+                                              ty::TypeAndMut {
+                                                  ty: var_ty,
+                                                  mutbl: borrow.kind.to_mutbl_lossy(),
+                                              }),
                             span: expr.span,
                             kind: field_kind,
-                        }.to_ref()
+                        }.to_ref(),
                     }
                 }
             }
@@ -863,86 +831,58 @@ fn bin_op(op: hir::BinOp_) -> BinOp {
     }
 }
 
-enum PassArgs {
-    ByValue,
-    ByRef,
-}
-
 fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                        expr: &'tcx hir::Expr,
-                                       method_call: ty::MethodCall,
-                                       pass_args: PassArgs,
-                                       receiver: ExprRef<'tcx>,
-                                       args: Vec<&'tcx P<hir::Expr>>)
+                                       args: Vec<ExprRef<'tcx>>)
                                        -> ExprKind<'tcx> {
-    // the receiver has all the adjustments that are needed, so we can
-    // just push a reference to it
-    let mut argrefs = vec![receiver];
-
-    // the arguments, unfortunately, do not, so if this is a ByRef
-    // operator, we have to gin up the autorefs (but by value is easy)
-    match pass_args {
-        PassArgs::ByValue => {
-            argrefs.extend(args.iter().map(|arg| arg.to_ref()))
-        }
-
-        PassArgs::ByRef => {
-            let region = cx.tcx.node_scope_region(expr.id);
-            let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
-            argrefs.extend(
-                args.iter()
-                    .map(|arg| {
-                        let arg_ty = cx.tcx.tables().expr_ty_adjusted(arg);
-                        let adjusted_ty =
-                            cx.tcx.mk_ref(region,
-                                       ty::TypeAndMut { ty: arg_ty,
-                                                        mutbl: hir::MutImmutable });
-                        Expr {
-                            temp_lifetime: temp_lifetime,
-                            ty: adjusted_ty,
-                            span: expr.span,
-                            kind: ExprKind::Borrow { region: region,
-                                                     borrow_kind: BorrowKind::Shared,
-                                                     arg: arg.to_ref() }
-                        }.to_ref()
-                    }))
-        }
-    }
-
-    // now create the call itself
-    let fun = method_callee(cx, expr, method_call);
+    let fun = method_callee(cx, expr, None);
     ExprKind::Call {
         ty: fun.ty,
         fun: fun.to_ref(),
-        args: argrefs,
+        args,
     }
 }
 
 fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                      expr: &'tcx hir::Expr,
-                                     method_call: ty::MethodCall,
-                                     pass_args: PassArgs,
-                                     receiver: ExprRef<'tcx>,
-                                     args: Vec<&'tcx P<hir::Expr>>)
+                                     lvalue_ty: Ty<'tcx>,
+                                     custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
+                                     args: Vec<ExprRef<'tcx>>)
                                      -> ExprKind<'tcx> {
     // For an overloaded *x or x[y] expression of type T, the method
     // call returns an &T and we must add the deref so that the types
     // line up (this is because `*x` and `x[y]` represent lvalues):
 
-    // to find the type &T of the content returned by the method;
-    let ref_ty = cx.tcx.tables().method_map[&method_call].ty.fn_ret();
-    let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap();
-    // callees always have all late-bound regions fully instantiated,
+    let recv_ty = match args[0] {
+        ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e),
+        ExprRef::Mirror(ref e) => e.ty
+    };
+
+    // Reconstruct the output assuming it's a reference with the
+    // same region and mutability as the receiver. This holds for
+    // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
+    let (region, mt) = match recv_ty.sty {
+        ty::TyRef(region, mt) => (region, mt),
+        _ => span_bug!(expr.span, "overloaded_lvalue: receiver is not a reference"),
+    };
+    let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut {
+        ty: lvalue_ty,
+        mutbl: mt.mutbl,
+    });
 
     // construct the complete expression `foo()` for the overloaded call,
     // which will yield the &T type
-    let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
-    let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
+    let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+    let fun = method_callee(cx, expr, custom_callee);
     let ref_expr = Expr {
-        temp_lifetime: temp_lifetime,
+        temp_lifetime,
         ty: ref_ty,
         span: expr.span,
-        kind: ref_kind,
+        kind: ExprKind::Call {
+            ty: fun.ty,
+            fun: fun.to_ref(),
+            args,
+        },
     };
 
     // construct and return a deref wrapper `*foo()`
@@ -954,24 +894,22 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                    freevar: &hir::Freevar,
                                    freevar_ty: Ty<'tcx>)
                                    -> ExprRef<'tcx> {
-    let id_var = cx.tcx.map.as_local_node_id(freevar.def.def_id()).unwrap();
+    let var_hir_id = cx.tcx.hir.node_to_hir_id(freevar.var_id());
     let upvar_id = ty::UpvarId {
-        var_id: id_var,
-        closure_expr_id: closure_expr.id,
+        var_id: var_hir_id,
+        closure_expr_id: cx.tcx.hir.local_def_id(closure_expr.id).index,
     };
-    let upvar_capture = cx.tcx.tables().upvar_capture(upvar_id).unwrap();
-    let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id);
-    let var_ty = cx.tcx.tables().node_id_to_type(id_var);
+    let upvar_capture = cx.tables().upvar_capture(upvar_id);
+    let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
+    let var_ty = cx.tables().node_id_to_type(var_hir_id);
     let captured_var = Expr {
-        temp_lifetime: temp_lifetime,
+        temp_lifetime,
         ty: var_ty,
         span: closure_expr.span,
         kind: convert_var(cx, closure_expr, freevar.def),
     };
     match upvar_capture {
-        ty::UpvarCapture::ByValue => {
-            captured_var.to_ref()
-        }
+        ty::UpvarCapture::ByValue => captured_var.to_ref(),
         ty::UpvarCapture::ByRef(upvar_borrow) => {
             let borrow_kind = match upvar_borrow.kind {
                 ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
@@ -979,34 +917,29 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 ty::BorrowKind::MutBorrow => BorrowKind::Mut,
             };
             Expr {
-                temp_lifetime: temp_lifetime,
+                temp_lifetime,
                 ty: freevar_ty,
                 span: closure_expr.span,
-                kind: ExprKind::Borrow { region: upvar_borrow.region,
-                                         borrow_kind: borrow_kind,
-                                         arg: captured_var.to_ref() }
+                kind: ExprKind::Borrow {
+                    region: upvar_borrow.region,
+                    borrow_kind,
+                    arg: captured_var.to_ref(),
+                },
             }.to_ref()
         }
     }
 }
 
-fn loop_label<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
-                              expr: &'tcx hir::Expr) -> CodeExtent {
-    match cx.tcx.expect_def(expr.id) {
-        Def::Label(loop_id) => cx.tcx.region_maps.node_extent(loop_id),
-        d => span_bug!(expr.span, "loop scope resolved to {:?}", d),
-    }
-}
-
 /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef.
-fn field_refs<'tcx>(variant: VariantDef<'tcx>,
+fn field_refs<'tcx>(variant: &'tcx VariantDef,
                     fields: &'tcx [hir::Field])
-                    -> Vec<FieldExprRef<'tcx>>
-{
+                    -> Vec<FieldExprRef<'tcx>> {
     fields.iter()
-          .map(|field| FieldExprRef {
-              name: Field::new(variant.index_of_field_named(field.name.node).unwrap()),
-              expr: field.expr.to_ref(),
-          })
-          .collect()
+        .map(|field| {
+            FieldExprRef {
+                name: Field::new(variant.index_of_field_named(field.name.node).unwrap()),
+                expr: field.expr.to_ref(),
+            }
+        })
+        .collect()
 }