about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2017-05-19 12:46:34 +0300
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2017-06-01 08:59:47 +0300
commita65ced5d161d31e7e5b097b36bff0f51ec0843bc (patch)
treefb17e25a985507172f83a6ed3aa84783a4d08fad /src
parent22510f32666d0c9c230c9d09e5bcd9eb3a6200b3 (diff)
downloadrust-a65ced5d161d31e7e5b097b36bff0f51ec0843bc.tar.gz
rust-a65ced5d161d31e7e5b097b36bff0f51ec0843bc.zip
rustc: avoid using MethodCallee's signature where possible.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/cfg/construct.rs7
-rw-r--r--src/librustc/middle/effect.rs7
-rw-r--r--src/librustc/middle/expr_use_visitor.rs4
-rw-r--r--src/librustc/middle/liveness.rs7
-rw-r--r--src/librustc/middle/mem_categorization.rs205
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs4
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs8
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs36
-rw-r--r--src/librustc_typeck/check/regionck.rs26
12 files changed, 147 insertions, 163 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 2246621f83c..affc84382a5 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -412,15 +412,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             pred: CFGIndex,
             func_or_rcvr: &hir::Expr,
             args: I) -> CFGIndex {
-        let fn_ty = match self.tables.method_map.get(&call_expr.id) {
-            Some(method) => method.ty,
-            None => self.tables.expr_ty_adjusted(func_or_rcvr),
-        };
-
         let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
         let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
         // FIXME(canndrew): This is_never should probably be an is_uninhabited.
-        if fn_ty.fn_ret().0.is_never() {
+        if self.tables.expr_ty(call_expr).is_never() {
             self.add_unreachable_node()
         } else {
             ret
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index e84265cb60f..c9593e54a86 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -173,10 +173,11 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
             hir::ExprMethodCall(..) => {
-                let method_sig = self.tables.method_map[&expr.id].sig;
+                let method = self.tables.method_map[&expr.id];
+                let base_type = self.tcx.type_of(method.def_id);
                 debug!("effect: method call case, base type is {:?}",
-                        method_sig);
-                if method_sig.unsafety == hir::Unsafety::Unsafe {
+                        base_type);
+                if type_is_unsafe_function(base_type) {
                     self.require_unsafe(expr.span,
                                         "invocation of unsafe method")
                 }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 73598d0bb1a..45afc17f339 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -761,8 +761,10 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 let bk = ty::BorrowKind::from_mutbl(m);
                 self.delegate.borrow(expr.id, expr.span, cmt.clone(),
                                      r, bk, AutoRef);
+                cmt = self.mc.cat_overloaded_autoderef(expr, method)?;
+            } else {
+                cmt = self.mc.cat_deref(expr, cmt, false)?;
             }
-            cmt = self.mc.cat_deref(expr, cmt, overloaded)?;
         }
         Ok(cmt)
     }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index fd8ca332a64..6a74af6eb8a 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1072,9 +1072,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprCall(ref f, ref args) => {
             // FIXME(canndrew): This is_never should really be an is_uninhabited
-            let diverges = !self.tables.is_method_call(expr.id) &&
-                self.tables.expr_ty_adjusted(&f).fn_sig().output().0.is_never();
-            let succ = if diverges {
+            let succ = if self.tables.expr_ty(expr).is_never() {
                 self.s.exit_ln
             } else {
                 succ
@@ -1084,9 +1082,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           }
 
           hir::ExprMethodCall(.., ref args) => {
-            let ret_ty = self.tables.method_map[&expr.id].sig.output();
             // FIXME(canndrew): This is_never should really be an is_uninhabited
-            let succ = if ret_ty.is_never() {
+            let succ = if self.tables.expr_ty(expr).is_never() {
                 self.s.exit_ln
             } else {
                 succ
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index aa729c75796..cc65777bfce 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -63,7 +63,6 @@
 pub use self::PointerKind::*;
 pub use self::InteriorKind::*;
 pub use self::FieldName::*;
-pub use self::ElementKind::*;
 pub use self::MutabilityCategory::*;
 pub use self::AliasableReason::*;
 pub use self::Note::*;
@@ -129,7 +128,7 @@ pub enum PointerKind<'tcx> {
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum InteriorKind {
     InteriorField(FieldName),
-    InteriorElement(InteriorOffsetKind, ElementKind),
+    InteriorElement(InteriorOffsetKind),
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
@@ -145,12 +144,6 @@ pub enum InteriorOffsetKind {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub enum ElementKind {
-    VecElement,
-    OtherElement,
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub enum MutabilityCategory {
     McImmutable, // Immutable.
     McDeclared,  // Directly declared as mutable.
@@ -492,7 +485,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                         debug!("cat_expr: autoderefs={:?}, cmt={:?}",
                                autoderefs, cmt);
                         for &overloaded in autoderefs {
-                            cmt = self.cat_deref(expr, cmt, overloaded)?;
+                            if let Some(method) = overloaded {
+                                cmt = self.cat_overloaded_autoderef(expr, method)?;
+                            } else {
+                                cmt = self.cat_deref(expr, cmt, false)?;
+                            }
                         }
                         return Ok(cmt);
                     }
@@ -518,10 +515,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         let expr_ty = self.expr_ty(expr)?;
         match expr.node {
           hir::ExprUnary(hir::UnDeref, ref e_base) => {
-            let base_cmt = self.cat_expr(&e_base)?;
-            let method = self.infcx.tables.borrow().method_map
-                .get(&expr.id).cloned();
-            self.cat_deref(expr, base_cmt, method)
+            if self.infcx.tables.borrow().is_method_call(expr.id) {
+                self.cat_overloaded_lvalue(expr, e_base, false)
+            } else {
+                let base_cmt = self.cat_expr(&e_base)?;
+                self.cat_deref(expr, base_cmt, false)
+            }
           }
 
           hir::ExprField(ref base, f_name) => {
@@ -539,33 +538,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
           }
 
           hir::ExprIndex(ref base, _) => {
-            let method = self.infcx.tables.borrow().method_map.get(&expr.id()).cloned();
-            match method {
-                Some(method) => {
-                    // If this is an index implemented by a method call, then it
-                    // will include an implicit deref of the result.
-                    let ret_ty = self.overloaded_method_return_ty(method);
-
-                    // The index method always returns an `&T`, so
-                    // dereference it to find the result type.
-                    let elem_ty = match ret_ty.sty {
-                        ty::TyRef(_, mt) => mt.ty,
-                        _ => {
-                            debug!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
-                                   ret_ty);
-                            return Err(());
-                        }
-                    };
-
-                    // The call to index() returns a `&T` value, which
-                    // is an rvalue. That is what we will be
-                    // dereferencing.
-                    let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty);
-                    Ok(self.cat_deref_common(expr, base_cmt, elem_ty, true))
-                }
-                None => {
-                    self.cat_index(expr, self.cat_expr(&base)?, InteriorOffsetKind::Index)
-                }
+            if self.infcx.tables.borrow().is_method_call(expr.id()) {
+                // If this is an index implemented by a method call, then it
+                // will include an implicit deref of the result.
+                // The call to index() returns a `&T` value, which
+                // is an rvalue. That is what we will be
+                // dereferencing.
+                self.cat_overloaded_lvalue(expr, base, true)
+            } else {
+                let base_cmt = self.cat_expr(&base)?;
+                self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index)
             }
           }
 
@@ -924,42 +906,63 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         ret
     }
 
+    fn cat_overloaded_lvalue(&self,
+                             expr: &hir::Expr,
+                             base: &hir::Expr,
+                             implicit: bool)
+                             -> McResult<cmt<'tcx>> {
+        debug!("cat_overloaded_lvalue: implicit={}", implicit);
+
+        // 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 lvalue_ty = self.expr_ty(expr)?;
+        let base_ty = self.expr_ty_adjusted(base)?;
+
+        let (region, mutbl) = match base_ty.sty {
+            ty::TyRef(region, mt) => (region, mt.mutbl),
+            _ => {
+                span_bug!(expr.span, "cat_overloaded_lvalue: base is not a reference")
+            }
+        };
+        let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut {
+            ty: lvalue_ty,
+            mutbl,
+        });
+
+        let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty);
+        self.cat_deref(expr, base_cmt, implicit)
+    }
+
+    pub fn cat_overloaded_autoderef(&self,
+                                    expr: &hir::Expr,
+                                    method: ty::MethodCallee<'tcx>)
+                                    -> McResult<cmt<'tcx>> {
+        debug!("cat_overloaded_autoderef: method={:?}", method);
+
+        let ref_ty = method.sig.output();
+        let ref_ty = self.infcx.resolve_type_vars_if_possible(&ref_ty);
+        let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty);
+        self.cat_deref(expr, base_cmt, false)
+    }
+
     pub fn cat_deref<N:ast_node>(&self,
                                  node: &N,
                                  base_cmt: cmt<'tcx>,
-                                 overloaded: Option<ty::MethodCallee<'tcx>>)
+                                 implicit: bool)
                                  -> McResult<cmt<'tcx>> {
-        debug!("cat_deref: overloaded={:?}", overloaded);
+        debug!("cat_deref: base_cmt={:?}", base_cmt);
 
-        let base_cmt = match overloaded {
-            Some(method) => {
-                let ref_ty = self.overloaded_method_return_ty(method);
-                self.cat_rvalue_node(node.id(), node.span(), ref_ty)
-            }
-            None => base_cmt
-        };
         let base_cmt_ty = base_cmt.ty;
-        match base_cmt_ty.builtin_deref(true, ty::NoPreference) {
-            Some(mt) => {
-                let ret = self.cat_deref_common(node, base_cmt, mt.ty, false);
-                debug!("cat_deref ret {:?}", ret);
-                Ok(ret)
-            }
+        let deref_ty = match base_cmt_ty.builtin_deref(true, ty::NoPreference) {
+            Some(mt) => mt.ty,
             None => {
                 debug!("Explicit deref of non-derefable type: {:?}",
                        base_cmt_ty);
                 return Err(());
             }
-        }
-    }
+        };
 
-    fn cat_deref_common<N:ast_node>(&self,
-                                    node: &N,
-                                    base_cmt: cmt<'tcx>,
-                                    deref_ty: Ty<'tcx>,
-                                    implicit: bool)
-                                    -> cmt<'tcx>
-    {
         let ptr = match base_cmt.ty.sty {
             ty::TyAdt(def, ..) if def.is_box() => Unique,
             ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl),
@@ -967,7 +970,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                 let bk = ty::BorrowKind::from_mutbl(mt.mutbl);
                 if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) }
             }
-            ref ty => bug!("unexpected type in cat_deref_common: {:?}", ty)
+            ref ty => bug!("unexpected type in cat_deref: {:?}", ty)
         };
         let ret = Rc::new(cmt_ {
             id: node.id(),
@@ -978,15 +981,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             ty: deref_ty,
             note: NoteNone
         });
-        debug!("cat_deref_common ret {:?}", ret);
-        ret
+        debug!("cat_deref ret {:?}", ret);
+        Ok(ret)
     }
 
-    pub fn cat_index<N:ast_node>(&self,
-                                 elt: &N,
-                                 mut base_cmt: cmt<'tcx>,
-                                 context: InteriorOffsetKind)
-                                 -> McResult<cmt<'tcx>> {
+    fn cat_index<N:ast_node>(&self,
+                             elt: &N,
+                             base_cmt: cmt<'tcx>,
+                             element_ty: Ty<'tcx>,
+                             context: InteriorOffsetKind)
+                             -> McResult<cmt<'tcx>> {
         //! Creates a cmt for an indexing operation (`[]`).
         //!
         //! One subtle aspect of indexing that may not be
@@ -1004,29 +1008,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         //! - `elt`: the AST node being indexed
         //! - `base_cmt`: the cmt of `elt`
 
-        let method = self.infcx.tables.borrow().method_map.get(&elt.id()).cloned();
-        let (element_ty, element_kind) = match method {
-            Some(method) => {
-                let ref_ty = self.overloaded_method_return_ty(method);
-                base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
-
-                (ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty,
-                 ElementKind::OtherElement)
-            }
-            None => {
-                match base_cmt.ty.builtin_index() {
-                    Some(ty) => (ty, ElementKind::VecElement),
-                    None => {
-                        debug!("Explicit index of non-indexable type {:?}", base_cmt);
-                        return Err(());
-                    }
-                }
-            }
-        };
-
-        let interior_elem = InteriorElement(context, element_kind);
+        let interior_elem = InteriorElement(context);
         let ret =
-            self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem);
+            self.cat_imm_interior(elt, base_cmt, element_ty, interior_elem);
         debug!("cat_index ret {:?}", ret);
         return Ok(ret);
     }
@@ -1216,15 +1200,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             // box p1, &p1, &mut p1.  we can ignore the mutability of
             // PatKind::Ref since that information is already contained
             // in the type.
-            let method = self.infcx.tables.borrow().method_map
-                .get(&pat.id).cloned();
-            let subcmt = self.cat_deref(pat, cmt, method)?;
+            let subcmt = self.cat_deref(pat, cmt, false)?;
             self.cat_pattern_(subcmt, &subpat, op)?;
           }
 
           PatKind::Slice(ref before, ref slice, ref after) => {
+            let element_ty = match cmt.ty.builtin_index() {
+                Some(ty) => ty,
+                None => {
+                    debug!("Explicit index of non-indexable type {:?}", cmt);
+                    return Err(());
+                }
+            };
             let context = InteriorOffsetKind::Pattern;
-            let elt_cmt = self.cat_index(pat, cmt, context)?;
+            let elt_cmt = self.cat_index(pat, cmt, element_ty, context)?;
             for before_pat in before {
                 self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
             }
@@ -1244,16 +1233,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         Ok(())
     }
-
-    fn overloaded_method_return_ty(&self,
-                                   method: ty::MethodCallee<'tcx>)
-                                   -> Ty<'tcx>
-    {
-        // When we process an overloaded `*` or `[]` etc, we often
-        // need to extract the return type of the method.
-        let ret_ty = method.sig.output();
-        self.infcx.resolve_type_vars_if_possible(&ret_ty)
-    }
 }
 
 #[derive(Clone, Debug)]
@@ -1401,16 +1380,10 @@ impl<'tcx> cmt_<'tcx> {
             Categorization::Interior(_, InteriorField(PositionalField(_))) => {
                 "anonymous field".to_string()
             }
-            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index,
-                                                        VecElement)) |
-            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index,
-                                                        OtherElement)) => {
+            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index)) => {
                 "indexed content".to_string()
             }
-            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern,
-                                                        VecElement)) |
-            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern,
-                                                        OtherElement)) => {
+            Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern)) => {
                 "pattern-bound indexed content".to_string()
             }
             Categorization::Upvar(ref var) => {
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 722ec6424fe..0fe8865f4a2 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -805,7 +805,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                 self.check_if_assigned_path_is_moved(id, span,
                                                      use_kind, lp_base);
             }
-            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) |
+            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) |
             LpExtend(ref lp_base, _, LpDeref(_)) => {
                 // assigning to `P[i]` requires `P` is initialized
                 // assigning to `(*P)` requires `P` is initialized
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index baa18307510..3d98c2a23dc 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -237,7 +237,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
         Categorization::Downcast(ref b, _) |
         Categorization::Interior(ref b, mc::InteriorField(_)) |
-        Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
+        Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern)) => {
             match b.ty.sty {
                 ty::TyAdt(def, _) => {
                     if def.has_dtor(bccx.tcx) {
@@ -253,7 +253,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             }
         }
 
-        Categorization::Interior(_, mc::InteriorElement(Kind::Index, _)) => {
+        Categorization::Interior(_, mc::InteriorElement(Kind::Index)) => {
             // Forbid move of arr[i] for arr: [T; 3]; see RFC 533.
             Some(cmt.clone())
         }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index f7c3bb36da7..cceb4a7b3cc 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -152,7 +152,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             err
         }
 
-        Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => {
+        Categorization::Interior(ref b, mc::InteriorElement(ik)) => {
             match (&b.ty.sty, ik) {
                 (&ty::TySlice(..), _) |
                 (_, Kind::Index) => {
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 0b2cb1b93f9..2b5bbe0e8a5 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -284,7 +284,7 @@ const DOWNCAST_PRINTED_OPERATOR: &'static str = " as ";
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum InteriorKind {
     InteriorField(mc::FieldName),
-    InteriorElement(mc::ElementKind),
+    InteriorElement,
 }
 
 trait ToInteriorKind { fn cleaned(self) -> InteriorKind; }
@@ -292,7 +292,7 @@ impl ToInteriorKind for mc::InteriorKind {
     fn cleaned(self) -> InteriorKind {
         match self {
             mc::InteriorField(name) => InteriorField(name),
-            mc::InteriorElement(_, elem_kind) => InteriorElement(elem_kind),
+            mc::InteriorElement(_) => InteriorElement,
         }
     }
 }
@@ -1232,7 +1232,7 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
                 }
             }
 
-            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement(..))) => {
+            LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => {
                 self.append_autoderefd_loan_path_to_string(&lp_base, out);
                 out.push_str("[..]");
             }
@@ -1318,7 +1318,7 @@ impl<'tcx> fmt::Debug for InteriorKind {
         match *self {
             InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld),
             InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i),
-            InteriorElement(..) => write!(f, "[]"),
+            InteriorElement => write!(f, "[]"),
         }
     }
 }
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 1b364596a23..0a31905c792 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -191,7 +191,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
         LpVar(_) | LpUpvar(_) => {
             true
         }
-        LpExtend(.., LpInterior(_, InteriorKind::InteriorElement(..))) => {
+        LpExtend(.., LpInterior(_, InteriorKind::InteriorElement)) => {
             // Paths involving element accesses a[i] do not refer to a unique
             // location, as there is no accurate tracking of the indices.
             //
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 6428146525c..eee1f1a9712 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -94,8 +94,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                         debug!("make_mirror: overloaded autoderef (method={:?})", method);
 
                         ref_ty = method.sig.output();
-                        let (region, mutbl) = match ref_ty.sty {
-                            ty::TyRef(region, mt) => (region, mt.mutbl),
+                        let (region, mt) = match ref_ty.sty {
+                            ty::TyRef(region, mt) => (region, mt),
                             _ => span_bug!(expr.span, "autoderef returned bad type"),
                         };
 
@@ -105,18 +105,19 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
                             ty: cx.tcx.mk_ref(region,
                                               ty::TypeAndMut {
                                                   ty: expr.ty,
-                                                  mutbl: mutbl,
+                                                  mutbl: mt.mutbl,
                                               }),
                             span: expr.span,
                             kind: ExprKind::Borrow {
                                 region: region,
-                                borrow_kind: to_borrow_kind(mutbl),
+                                borrow_kind: to_borrow_kind(mt.mutbl),
                                 arg: expr.to_ref(),
                             },
                         };
 
                         overloaded_lvalue(cx,
                                           self,
+                                          mt.ty,
                                           method,
                                           PassArgs::ByRef,
                                           expr.to_ref(),
@@ -264,13 +265,11 @@ 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 sig = method.sig;
                 let method = method_callee(cx, expr, method);
 
-                assert_eq!(sig.inputs().len(), 2);
-
+                let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e));
                 let tupled_args = Expr {
-                    ty: sig.inputs()[1],
+                    ty: cx.tcx.mk_tup(arg_tys, false),
                     temp_lifetime: temp_lifetime,
                     temp_lifetime_was_shrunk: was_shrunk,
                     span: expr.span,
@@ -435,6 +434,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             if let Some(&method) = cx.tables().method_map.get(&expr.id) {
                 overloaded_lvalue(cx,
                                   expr,
+                                  expr_ty,
                                   method,
                                   PassArgs::ByValue,
                                   lhs.to_ref(),
@@ -451,6 +451,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             if let Some(&method) = cx.tables().method_map.get(&expr.id) {
                 overloaded_lvalue(cx,
                                   expr,
+                                  expr_ty,
                                   method,
                                   PassArgs::ByValue,
                                   arg.to_ref(),
@@ -996,6 +997,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
 fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                      expr: &'tcx hir::Expr,
+                                     lvalue_ty: Ty<'tcx>,
                                      method: ty::MethodCallee<'tcx>,
                                      pass_args: PassArgs,
                                      receiver: ExprRef<'tcx>,
@@ -1005,8 +1007,22 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     // 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 = method.sig.output();
+    let recv_ty = match receiver {
+        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, mutbl) = match recv_ty.sty {
+        ty::TyRef(region, mt) => (region, mt.mutbl),
+        _ => 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,
+    });
 
     // construct the complete expression `foo()` for the overloaded call,
     // which will yield the &T type
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 9b609cac2fc..5cda50b428b 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -538,10 +538,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
             };
 
             self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region);
-            for &ty in callee.sig.inputs() {
-                self.type_must_outlive(infer::ExprTypeIsNotInScope(ty, expr.span),
-                                       ty, expr_region);
-            }
+            // Arguments (sub-expressions) are checked via `constrain_call`, below.
         }
 
         // Check any autoderefs or autorefs that appear.
@@ -690,14 +687,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
 
             hir::ExprUnary(hir::UnDeref, ref base) => {
                 // For *a, the lifetime of a must enclose the deref
-                let base_ty = match self.tables.borrow().method_map.get(&expr.id) {
-                    Some(method) => {
-                        self.constrain_call(expr, Some(&base),
-                                            None::<hir::Expr>.iter(), true);
-                        method.sig.output()
-                    }
-                    None => self.resolve_node_type(base.id)
-                };
+                if self.tables.borrow().is_method_call(expr.id) {
+                    self.constrain_call(expr, Some(base),
+                                        None::<hir::Expr>.iter(), true);
+                }
+                // For overloaded derefs, base_ty is the input to `Deref::deref`,
+                // but it's a reference type uing the same region as the output.
+                let base_ty = self.resolve_expr_type_adjusted(base);
                 if let ty::TyRef(r_ptr, _) = base_ty.sty {
                     self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr);
                 }
@@ -960,7 +956,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
             {
                 let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
-                cmt = mc.cat_deref(deref_expr, cmt, overloaded)?;
+                if let Some(method) = overloaded {
+                    cmt = mc.cat_overloaded_autoderef(deref_expr, method)?;
+                } else {
+                    cmt = mc.cat_deref(deref_expr, cmt, false)?;
+                }
             }
 
             if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat {