about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-10-31 05:44:10 -0400
committerNiko Matsakis <niko@alum.mit.edu>2014-11-05 11:29:15 -0500
commit0b5bc3314fa9bf768163828a8e38bac588936fe9 (patch)
tree5e080bbbd80c8e71da11c4aef39a2170b414c1ba
parent33ef78fa8bbe9b8d05ba0da607d4da5e31475a95 (diff)
downloadrust-0b5bc3314fa9bf768163828a8e38bac588936fe9.tar.gz
rust-0b5bc3314fa9bf768163828a8e38bac588936fe9.zip
Implement new operator dispatch semantics.
Key points are:
1. `a + b` maps directly to `Add<A,B>`, where `A` and `B` are the types of `a` and `b`.
2. Indexing and slicing autoderefs consistently.
-rw-r--r--src/librustc/middle/ty.rs15
-rw-r--r--src/librustc/middle/typeck/check/method.rs291
-rw-r--r--src/librustc/middle/typeck/check/mod.rs486
-rw-r--r--src/librustc/util/ppaux.rs7
-rw-r--r--src/test/compile-fail/borrowck-overloaded-index-autoderef.rs91
-rw-r--r--src/test/compile-fail/issue-13482-2.rs2
-rw-r--r--src/test/compile-fail/issue-15207.rs1
-rw-r--r--src/test/compile-fail/issue-17033.rs2
-rw-r--r--src/test/compile-fail/issue-2149.rs1
-rw-r--r--src/test/compile-fail/slice-mut-2.rs2
-rw-r--r--src/test/compile-fail/type-params-in-different-spaces-1.rs2
-rw-r--r--src/test/run-pass/overloaded-index-assoc-list.rs (renamed from src/test/run-pass/overload-index-operator.rs)0
-rw-r--r--src/test/run-pass/overloaded-index-autoderef.rs79
-rw-r--r--src/test/run-pass/overloaded-index-in-field.rs52
-rw-r--r--src/test/run-pass/overloaded-index.rs17
15 files changed, 827 insertions, 221 deletions
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index bdb9ef8e710..23a52895935 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -5566,3 +5566,18 @@ pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[Freevar]| -> T)
         Some(d) => f(d.as_slice())
     }
 }
+
+impl AutoAdjustment {
+    pub fn is_identity(&self) -> bool {
+        match *self {
+            AdjustAddEnv(..) => false,
+            AdjustDerefRef(ref r) => r.is_identity(),
+        }
+    }
+}
+
+impl AutoDerefRef {
+    pub fn is_identity(&self) -> bool {
+        self.autoderefs == 0 && self.autoref.is_none()
+    }
+}
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index 4334cf7db7a..abffa857a08 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -96,6 +96,7 @@ use middle::typeck::{MethodOrigin, MethodParam, MethodTypeParam};
 use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject};
 use middle::typeck::check::regionmanip::replace_late_bound_regions;
 use middle::typeck::TypeAndSubsts;
+use middle::typeck::check::vtable;
 use middle::ty_fold::TypeFoldable;
 use util::common::indenter;
 use util::ppaux;
@@ -173,46 +174,178 @@ pub fn lookup<'a, 'tcx>(
 
 pub fn lookup_in_trait<'a, 'tcx>(
     fcx: &'a FnCtxt<'a, 'tcx>,
-
-    // In a call `a.b::<X, Y, ...>(...)`:
-    span: Span,                         // The expression `a.b(...)`'s span.
-    self_expr: Option<&'a ast::Expr>,   // The expression `a`, if available.
-    m_name: ast::Name,                  // The name `b`.
-    trait_did: DefId,                   // The trait to limit the lookup to.
-    self_ty: ty::t,                     // The type of `a`.
-    supplied_tps: &'a [ty::t])          // The list of types X, Y, ... .
+    span: Span,
+    self_expr: Option<&'a ast::Expr>,
+    m_name: ast::Name,
+    trait_def_id: DefId,
+    self_ty: ty::t,
+    opt_input_types: Option<Vec<ty::t>>)
     -> Option<MethodCallee>
 {
-    let mut lcx = LookupContext {
-        fcx: fcx,
-        span: span,
-        self_expr: self_expr,
-        m_name: m_name,
-        supplied_tps: supplied_tps,
-        impl_dups: HashSet::new(),
-        inherent_candidates: Vec::new(),
-        extension_candidates: Vec::new(),
-        static_candidates: Vec::new(),
-        deref_args: check::DoDerefArgs,
-        check_traits: CheckTraitsOnly,
-        autoderef_receiver: DontAutoderefReceiver,
-    };
+    lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id,
+                             ty::AutoDerefRef { autoderefs: 0, autoref: None },
+                             self_ty, opt_input_types)
+}
 
-    debug!("method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_did={})",
+pub fn lookup_in_trait_adjusted<'a, 'tcx>(
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    span: Span,
+    self_expr: Option<&'a ast::Expr>,
+    m_name: ast::Name,
+    trait_def_id: DefId,
+    autoderefref: ty::AutoDerefRef,
+    self_ty: ty::t,
+    opt_input_types: Option<Vec<ty::t>>)
+    -> Option<MethodCallee>
+{
+    debug!("method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_def_id={})",
            self_ty.repr(fcx.tcx()),
            self_expr.repr(fcx.tcx()),
            m_name.repr(fcx.tcx()),
-           trait_did.repr(fcx.tcx()));
+           trait_def_id.repr(fcx.tcx()));
+
+    let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_def_id);
+
+    let expected_number_of_input_types = trait_def.generics.types.len(subst::TypeSpace);
+    let input_types = match opt_input_types {
+        Some(input_types) => {
+            assert_eq!(expected_number_of_input_types, input_types.len());
+            input_types
+        }
+
+        None => {
+            fcx.inh.infcx.next_ty_vars(expected_number_of_input_types)
+        }
+    };
+
+    let number_assoc_types = trait_def.generics.types.len(subst::AssocSpace);
+    let assoc_types = fcx.inh.infcx.next_ty_vars(number_assoc_types);
 
-    lcx.push_bound_candidates(self_ty, Some(trait_did));
-    lcx.push_extension_candidate(trait_did);
+    assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0);
+    assert!(trait_def.generics.regions.is_empty());
 
-    // when doing a trait search, ambiguity can't really happen except
-    // as part of the trait-lookup in general
-    match lcx.search(self_ty) {
-        Ok(callee) => Some(callee),
-        Err(_) => None
+    // Construct a trait-reference `self_ty : Trait<input_tys>`
+    let substs = subst::Substs::new_trait(input_types, Vec::new(), assoc_types, self_ty);
+    let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs));
+
+    // Construct an obligation
+    let obligation = traits::Obligation::misc(span, trait_ref.clone());
+
+    // Now we want to know if this can be matched
+    let mut selcx = traits::SelectionContext::new(fcx.infcx(),
+                                                  &fcx.inh.param_env,
+                                                  fcx);
+    if !selcx.evaluate_obligation_intracrate(&obligation) {
+        debug!("--> Cannot match obligation");
+        return None; // Cannot be matched, no such method resolution is possible.
+    }
+
+    // Trait must have a method named `m_name` and it should not have
+    // type parameters or early-bound regions.
+    let tcx = fcx.tcx();
+    let (method_num, method_ty) = trait_method(tcx, trait_def_id, m_name).unwrap();
+    assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
+    assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
+
+    // Substitute the trait parameters into the method type and
+    // instantiate late-bound regions to get the actual method type.
+    let ref bare_fn_ty = method_ty.fty;
+    let fn_sig = bare_fn_ty.sig.subst(tcx, &trait_ref.substs);
+    let fn_sig = replace_late_bound_regions_with_fresh_var(fcx.infcx(), span,
+                                                           fn_sig.binder_id, &fn_sig);
+    let transformed_self_ty = fn_sig.inputs[0];
+    let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
+        sig: fn_sig,
+        fn_style: bare_fn_ty.fn_style,
+        abi: bare_fn_ty.abi.clone(),
+    });
+
+    debug!("matched method fty={} obligation={}",
+           fty.repr(fcx.tcx()),
+           obligation.repr(fcx.tcx()));
+
+    // Register obligations for the parameters.  This will include the
+    // `Self` parameter, which in turn has a bound of the main trait,
+    // so this also effectively registers `obligation` as well.  (We
+    // used to register `obligation` explicitly, but that resulted in
+    // double error messages being reported.)
+    fcx.add_obligations_for_parameters(
+        traits::ObligationCause::misc(span),
+        &trait_ref.substs,
+        &method_ty.generics);
+
+    // FIXME(#18653) -- Try to resolve obligations, giving us more
+    // typing information, which can sometimes be needed to avoid
+    // pathological region inference failures.
+    vtable::select_new_fcx_obligations(fcx);
+
+    // Insert any adjustments needed (always an autoref of some mutability).
+    match self_expr {
+        None => { }
+
+        Some(self_expr) => {
+            debug!("inserting adjustment if needed (self-id = {}, \
+                   base adjustment = {}, explicit self = {})",
+                   self_expr.id, autoderefref, method_ty.explicit_self);
+
+            match method_ty.explicit_self {
+                ty::ByValueExplicitSelfCategory => {
+                    // Trait method is fn(self), no transformation needed.
+                    if !autoderefref.is_identity() {
+                        fcx.write_adjustment(
+                            self_expr.id,
+                            span,
+                            ty::AdjustDerefRef(autoderefref));
+                    }
+                }
+
+                ty::ByReferenceExplicitSelfCategory(..) => {
+                    // Trait method is fn(&self) or fn(&mut self), need an
+                    // autoref. Pull the region etc out of the type of first argument.
+                    match ty::get(transformed_self_ty).sty {
+                        ty::ty_rptr(region, ty::mt { mutbl, ty: _ }) => {
+                            let ty::AutoDerefRef { autoderefs, autoref } = autoderefref;
+                            let autoref = autoref.map(|r| box r);
+                            fcx.write_adjustment(
+                                self_expr.id,
+                                span,
+                                ty::AdjustDerefRef(ty::AutoDerefRef {
+                                    autoderefs: autoderefs,
+                                    autoref: Some(ty::AutoPtr(region, mutbl, autoref))
+                                }));
+                        }
+
+                        _ => {
+                            fcx.tcx().sess.span_bug(
+                                span,
+                                format!(
+                                    "trait method is &self but first arg is: {}",
+                                    transformed_self_ty.repr(fcx.tcx())).as_slice());
+                        }
+                    }
+                }
+
+                _ => {
+                    fcx.tcx().sess.span_bug(
+                        span,
+                        format!(
+                            "unexpected explicit self type in operator method: {}",
+                            method_ty.explicit_self).as_slice());
+                }
+            }
+        }
     }
+
+    let callee = MethodCallee {
+        origin: MethodTypeParam(MethodParam{trait_ref: trait_ref.clone(),
+                                            method_num: method_num}),
+        ty: fty,
+        substs: trait_ref.substs.clone()
+    };
+
+    debug!("callee = {}", callee.repr(fcx.tcx()));
+
+    Some(callee)
 }
 
 pub fn report_error(fcx: &FnCtxt,
@@ -1446,9 +1579,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
         }
     }
 
-    fn fixup_derefs_on_method_receiver_if_necessary(
-            &self,
-            method_callee: &MethodCallee) {
+    fn fixup_derefs_on_method_receiver_if_necessary(&self,
+                                                    method_callee: &MethodCallee) {
         let sig = match ty::get(method_callee.ty).sty {
             ty::ty_bare_fn(ref f) => f.sig.clone(),
             ty::ty_closure(ref f) => f.sig.clone(),
@@ -1485,6 +1617,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
             }
         }
 
+        debug!("fixup_derefs_on_method_receiver_if_necessary: exprs={}",
+               exprs.repr(self.tcx()));
+
         // Fix up autoderefs and derefs.
         for (i, expr) in exprs.iter().rev().enumerate() {
             // Count autoderefs.
@@ -1500,6 +1635,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
                 Some(_) | None => 0,
             };
 
+            debug!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={} autoderef_count={}",
+                   i, expr.repr(self.tcx()), autoderef_count);
+
             if autoderef_count > 0 {
                 check::autoderef(self.fcx,
                                  expr.span,
@@ -1518,24 +1656,59 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
             // Don't retry the first one or we might infinite loop!
             if i != 0 {
                 match expr.node {
-                    ast::ExprIndex(ref base_expr, ref index_expr) => {
-                        check::try_overloaded_index(
-                                self.fcx,
-                                Some(MethodCall::expr(expr.id)),
-                                *expr,
+                    ast::ExprIndex(ref base_expr, _) => {
+                        let mut base_adjustment =
+                            match self.fcx.inh.adjustments.borrow().find(&base_expr.id) {
+                                Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(),
+                                None => ty::AutoDerefRef { autoderefs: 0, autoref: None },
+                                Some(_) => {
+                                    self.tcx().sess.span_bug(
+                                        base_expr.span,
+                                        "unexpected adjustment type");
+                                }
+                            };
+
+                        // If this is an overloaded index, the
+                        // adjustment will include an extra layer of
+                        // autoref because the method is an &self/&mut
+                        // self method. We have to peel it off to get
+                        // the raw adjustment that `try_index_step`
+                        // expects. This is annoying and horrible. We
+                        // ought to recode this routine so it doesn't
+                        // (ab)use the normal type checking paths.
+                        base_adjustment.autoref = match base_adjustment.autoref {
+                            None => { None }
+                            Some(AutoPtr(_, _, None)) => { None }
+                            Some(AutoPtr(_, _, Some(box r))) => { Some(r) }
+                            Some(_) => {
+                                self.tcx().sess.span_bug(
+                                    base_expr.span,
+                                    "unexpected adjustment autoref");
+                            }
+                        };
+
+                        let adjusted_base_ty =
+                            self.fcx.adjust_expr_ty(
                                 &**base_expr,
-                                self.fcx.expr_ty(&**base_expr),
-                                index_expr,
-                                PreferMutLvalue);
+                                Some(&ty::AdjustDerefRef(base_adjustment.clone())));
+
+                        check::try_index_step(
+                            self.fcx,
+                            MethodCall::expr(expr.id),
+                            *expr,
+                            &**base_expr,
+                            adjusted_base_ty,
+                            base_adjustment,
+                            PreferMutLvalue);
                     }
                     ast::ExprUnary(ast::UnDeref, ref base_expr) => {
                         check::try_overloaded_deref(
-                                self.fcx,
-                                expr.span,
-                                Some(MethodCall::expr(expr.id)),
-                                Some(&**base_expr),
-                                self.fcx.expr_ty(&**base_expr),
-                                PreferMutLvalue);
+                            self.fcx,
+                            expr.span,
+                            Some(MethodCall::expr(expr.id)),
+                            Some(&**base_expr),
+                            self.fcx.expr_ty(&**base_expr),
+                            PreferMutLvalue);
                     }
                     _ => {}
                 }
@@ -1623,15 +1796,25 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
     fn replace_late_bound_regions_with_fresh_var<T>(&self, binder_id: ast::NodeId, value: &T) -> T
         where T : TypeFoldable + Repr
     {
-        let (_, value) = replace_late_bound_regions(
-            self.fcx.tcx(),
-            binder_id,
-            value,
-            |br| self.fcx.infcx().next_region_var(infer::LateBoundRegion(self.span, br)));
-        value
+        replace_late_bound_regions_with_fresh_var(self.fcx.infcx(), self.span, binder_id, value)
     }
 }
 
+fn replace_late_bound_regions_with_fresh_var<T>(infcx: &infer::InferCtxt,
+                                                span: Span,
+                                                binder_id: ast::NodeId,
+                                                value: &T)
+                                                -> T
+    where T : TypeFoldable + Repr
+{
+    let (_, value) = replace_late_bound_regions(
+        infcx.tcx,
+        binder_id,
+        value,
+        |br| infcx.next_region_var(infer::LateBoundRegion(span, br)));
+    value
+}
+
 fn trait_method(tcx: &ty::ctxt,
                 trait_def_id: ast::DefId,
                 method_name: ast::Name)
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 0c7de4b3ac4..0e3a77ba963 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -1630,6 +1630,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             adj: ty::AutoAdjustment) {
         debug!("write_adjustment(node_id={}, adj={})", node_id, adj);
 
+        if adj.is_identity() {
+            return;
+        }
+
         // Careful: adjustments can imply trait obligations if we are
         // casting from a concrete type to an object type. I think
         // it'd probably be nicer to move the logic that creates the
@@ -1813,6 +1817,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    pub fn expr_ty_adjusted(&self, expr: &ast::Expr) -> ty::t {
+        /*!
+         * Fetch type of `expr` after applying adjustments that
+         * have been recorded in the fcx.
+         */
+
+        let adjustments = self.inh.adjustments.borrow();
+        let adjustment = adjustments.find(&expr.id);
+        self.adjust_expr_ty(expr, adjustment)
+    }
+
+    pub fn adjust_expr_ty(&self,
+                          expr: &ast::Expr,
+                          adjustment: Option<&ty::AutoAdjustment>)
+                          -> ty::t
+    {
+        /*!
+         * Apply `adjustment` to the type of `expr`
+         */
+
+        let raw_ty = self.expr_ty(expr);
+        let raw_ty = self.infcx().shallow_resolve(raw_ty);
+        ty::adjust_ty(self.tcx(),
+                      expr.span,
+                      expr.id,
+                      raw_ty,
+                      adjustment,
+                      |method_call| self.inh.method_map.borrow()
+                                                       .find(&method_call)
+                                                       .map(|method| method.ty))
+    }
+
     pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
         match self.inh.node_types.borrow().find(&id) {
             Some(&t) => t,
@@ -2062,6 +2098,10 @@ pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
     for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
         let resolved_t = structurally_resolved_type(fcx, sp, t);
 
+        if ty::type_is_error(resolved_t) {
+            return (resolved_t, autoderefs, None);
+        }
+
         match should_stop(resolved_t, autoderefs) {
             Some(x) => return (resolved_t, autoderefs, Some(x)),
             None => {}
@@ -2117,17 +2157,17 @@ fn try_overloaded_call<'a>(fcx: &FnCtxt,
             None => continue,
             Some(function_trait) => function_trait,
         };
-        let method_callee = match method::lookup_in_trait(
-                fcx,
-                call_expression.span,
-                Some(&*callee),
-                method_name,
-                function_trait,
-                callee_type,
-                []) {
-            None => continue,
-            Some(method_callee) => method_callee,
-        };
+        let method_callee =
+            match method::lookup_in_trait(fcx,
+                                          call_expression.span,
+                                          Some(&*callee),
+                                          method_name,
+                                          function_trait,
+                                          callee_type,
+                                          None) {
+                None => continue,
+                Some(method_callee) => method_callee,
+            };
         let method_call = MethodCall::expr(call_expression.id);
         let output_type = check_method_argument_types(fcx,
                                                       call_expression.span,
@@ -2159,13 +2199,14 @@ fn try_overloaded_deref(fcx: &FnCtxt,
                         base_expr: Option<&ast::Expr>,
                         base_ty: ty::t,
                         lvalue_pref: LvaluePreference)
-                        -> Option<ty::mt> {
+                        -> Option<ty::mt>
+{
     // Try DerefMut first, if preferred.
     let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) {
         (PreferMutLvalue, Some(trait_did)) => {
             method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
                                     token::intern("deref_mut"), trait_did,
-                                    base_ty, [])
+                                    base_ty, None)
         }
         _ => None
     };
@@ -2175,25 +2216,27 @@ fn try_overloaded_deref(fcx: &FnCtxt,
         (None, Some(trait_did)) => {
             method::lookup_in_trait(fcx, span, base_expr.map(|x| &*x),
                                     token::intern("deref"), trait_did,
-                                    base_ty, [])
+                                    base_ty, None)
         }
         (method, _) => method
     };
 
-    make_return_type(fcx, method_call, method)
+    make_overloaded_lvalue_return_type(fcx, method_call, method)
 }
 
-fn get_method_ty(method: &Option<MethodCallee>) -> ty::t {
-    match method {
-        &Some(ref method) => method.ty,
-        &None => ty::mk_err()
-    }
-}
+fn make_overloaded_lvalue_return_type(fcx: &FnCtxt,
+                                      method_call: Option<MethodCall>,
+                                      method: Option<MethodCallee>)
+                                      -> Option<ty::mt>
+{
+    /*!
+     * For the overloaded lvalue expressions (`*x`, `x[3]`), the trait
+     * returns a type of `&T`, but the actual type we assign to the
+     * *expression* is `T`. So this function just peels off the return
+     * type by one layer to yield `T`. It also inserts the
+     * `method-callee` into the method map.
+     */
 
-fn make_return_type(fcx: &FnCtxt,
-                    method_call: Option<MethodCall>,
-                    method: Option<MethodCallee>)
-                    -> Option<ty::mt> {
     match method {
         Some(method) => {
             let ref_ty = ty::ty_fn_ret(method.ty);
@@ -2205,26 +2248,126 @@ fn make_return_type(fcx: &FnCtxt,
                 None => {}
             }
             match ref_ty {
-                ty::FnConverging(ref_ty) =>
-                    ty::deref(ref_ty, true),
-                ty::FnDiverging =>
-                    None
+                ty::FnConverging(ref_ty) => {
+                    ty::deref(ref_ty, true)
+                }
+                ty::FnDiverging => {
+                    fcx.tcx().sess.bug("index/deref traits do not define a `!` return")
+                }
             }
         }
         None => None,
     }
 }
 
+fn autoderef_for_index<T>(fcx: &FnCtxt,
+                          base_expr: &ast::Expr,
+                          base_ty: ty::t,
+                          lvalue_pref: LvaluePreference,
+                          step: |ty::t, ty::AutoDerefRef| -> Option<T>)
+                          -> Option<T>
+{
+    let (ty, autoderefs, final_mt) =
+        autoderef(fcx, base_expr.span, base_ty, Some(base_expr.id), lvalue_pref, |adj_ty, idx| {
+            let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None };
+            step(adj_ty, autoderefref)
+        });
+
+    if final_mt.is_some() {
+        return final_mt;
+    }
+
+    // After we have fully autoderef'd, if the resulting type is [T, ..n], then
+    // do a final unsized coercion to yield [T].
+    match ty::get(ty).sty {
+        ty::ty_vec(element_ty, Some(n)) => {
+            let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None);
+            let autoderefref = ty::AutoDerefRef {
+                autoderefs: autoderefs,
+                autoref: Some(ty::AutoUnsize(ty::UnsizeLength(n)))
+            };
+            step(adjusted_ty, autoderefref)
+        }
+        _ => {
+            None
+        }
+    }
+}
+
 fn try_overloaded_slice(fcx: &FnCtxt,
-                        method_call: Option<MethodCall>,
+                        method_call: MethodCall,
                         expr: &ast::Expr,
                         base_expr: &ast::Expr,
                         base_ty: ty::t,
                         start_expr: &Option<P<ast::Expr>>,
                         end_expr: &Option<P<ast::Expr>>,
-                        mutbl: &ast::Mutability)
-                        -> Option<ty::mt> {
-    let method = if mutbl == &ast::MutMutable {
+                        mutbl: ast::Mutability)
+                        -> Option<ty::t> // return type is result of slice
+{
+    /*!
+     * Autoderefs `base_expr`, looking for a `Slice` impl. If it
+     * finds one, installs the relevant method info and returns the
+     * result type (else None).
+     */
+
+    let lvalue_pref = match mutbl {
+        ast::MutMutable => PreferMutLvalue,
+        ast::MutImmutable => NoPreference
+    };
+
+    let opt_method_ty =
+        autoderef_for_index(fcx, base_expr, base_ty, lvalue_pref, |adjusted_ty, autoderefref| {
+            try_overloaded_slice_step(fcx, method_call, expr, base_expr,
+                                      adjusted_ty, autoderefref, mutbl,
+                                      start_expr, end_expr)
+        });
+
+    // Regardless of whether the lookup succeeds, check the method arguments
+    // so that we have *some* type for each argument.
+    let method_ty_or_err = opt_method_ty.unwrap_or(ty::mk_err());
+
+    let mut args = vec![];
+    start_expr.as_ref().map(|x| args.push(x));
+    end_expr.as_ref().map(|x| args.push(x));
+
+    check_method_argument_types(fcx,
+                                expr.span,
+                                method_ty_or_err,
+                                expr,
+                                args.as_slice(),
+                                DoDerefArgs,
+                                DontTupleArguments);
+
+    opt_method_ty.map(|method_ty| {
+        let result_ty = ty::ty_fn_ret(method_ty);
+        match result_ty {
+            ty::FnConverging(result_ty) => result_ty,
+            ty::FnDiverging => {
+                fcx.tcx().sess.span_bug(expr.span,
+                                        "slice trait does not define a `!` return")
+            }
+        }
+    })
+}
+
+fn try_overloaded_slice_step(fcx: &FnCtxt,
+                             method_call: MethodCall,
+                             expr: &ast::Expr,
+                             base_expr: &ast::Expr,
+                             base_ty: ty::t, // autoderef'd type
+                             autoderefref: ty::AutoDerefRef,
+                             mutbl: ast::Mutability,
+                             start_expr: &Option<P<ast::Expr>>,
+                             end_expr: &Option<P<ast::Expr>>)
+                             -> Option<ty::t> // result type is type of method being called
+{
+    /*!
+     * Checks for a `Slice` (or `SliceMut`) impl at the relevant level
+     * of autoderef. If it finds one, installs method info and returns
+     * type of method (else None).
+     */
+
+    let method = if mutbl == ast::MutMutable {
         // Try `SliceMut` first, if preferred.
         match fcx.tcx().lang_items.slice_mut_trait() {
             Some(trait_did) => {
@@ -2235,13 +2378,14 @@ fn try_overloaded_slice(fcx: &FnCtxt,
                     (&None, &None) => "as_mut_slice_",
                 };
 
-                method::lookup_in_trait(fcx,
-                                        expr.span,
-                                        Some(&*base_expr),
-                                        token::intern(method_name),
-                                        trait_did,
-                                        base_ty,
-                                        [])
+                method::lookup_in_trait_adjusted(fcx,
+                                                 expr.span,
+                                                 Some(&*base_expr),
+                                                 token::intern(method_name),
+                                                 trait_did,
+                                                 autoderefref,
+                                                 base_ty,
+                                                 None)
             }
             _ => None,
         }
@@ -2258,74 +2402,73 @@ fn try_overloaded_slice(fcx: &FnCtxt,
                     (&None, &None) => "as_slice_",
                 };
 
-                method::lookup_in_trait(fcx,
-                                        expr.span,
-                                        Some(&*base_expr),
-                                        token::intern(method_name),
-                                        trait_did,
-                                        base_ty,
-                                        [])
+                method::lookup_in_trait_adjusted(fcx,
+                                                 expr.span,
+                                                 Some(&*base_expr),
+                                                 token::intern(method_name),
+                                                 trait_did,
+                                                 autoderefref,
+                                                 base_ty,
+                                                 None)
             }
             _ => None,
         }
     };
 
+    // If some lookup succeeded, install method in table
+    method.map(|method| {
+        let ty = method.ty;
+        fcx.inh.method_map.borrow_mut().insert(method_call, method);
+        ty
+    })
+}
 
-    // Regardless of whether the lookup succeeds, check the method arguments
-    // so that we have *some* type for each argument.
-    let method_type = get_method_ty(&method);
-
-    let mut args = vec![];
-    start_expr.as_ref().map(|x| args.push(x));
-    end_expr.as_ref().map(|x| args.push(x));
+fn try_index_step(fcx: &FnCtxt,
+                  method_call: MethodCall,
+                  expr: &ast::Expr,
+                  base_expr: &ast::Expr,
+                  adjusted_ty: ty::t,
+                  adjustment: ty::AutoDerefRef,
+                  lvalue_pref: LvaluePreference)
+                  -> Option<(/*index type*/ ty::t, /*element type*/ ty::t)>
+{
+    /*!
+     * To type-check `base_expr[index_expr]`, we progressively autoderef (and otherwise adjust)
+     * `base_expr`, looking for a type which either supports builtin indexing or overloaded
+     * indexing. This loop implements one step in that search; the autoderef loop is implemented
+     * by `autoderef_for_index`.
+     */
 
-    check_method_argument_types(fcx,
-                                expr.span,
-                                method_type,
-                                expr,
-                                args.as_slice(),
-                                DoDerefArgs,
-                                DontTupleArguments);
+    debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, adjustment={})",
+           expr.repr(fcx.tcx()),
+           base_expr.repr(fcx.tcx()),
+           adjusted_ty.repr(fcx.tcx()),
+           adjustment);
 
-    match method {
-        Some(method) => {
-            let result_ty = ty::ty_fn_ret(method.ty);
-            match method_call {
-                Some(method_call) => {
-                    fcx.inh.method_map.borrow_mut().insert(method_call,
-                                                           method);
-                }
-                None => {}
-            }
-            match result_ty {
-                ty::FnConverging(result_ty) =>
-                    Some(ty::mt { ty: result_ty, mutbl: ast::MutImmutable }),
-                ty::FnDiverging =>
-                    None
-            }
+    // Try built-in indexing first.
+    match ty::index(adjusted_ty) {
+        Some(ty) => {
+            fcx.write_adjustment(base_expr.id, base_expr.span, ty::AdjustDerefRef(adjustment));
+            return Some((ty::mk_uint(), ty));
         }
-        None => None,
+
+        None => { }
     }
-}
 
-fn try_overloaded_index(fcx: &FnCtxt,
-                        method_call: Option<MethodCall>,
-                        expr: &ast::Expr,
-                        base_expr: &ast::Expr,
-                        base_ty: ty::t,
-                        index_expr: &P<ast::Expr>,
-                        lvalue_pref: LvaluePreference)
-                        -> Option<ty::mt> {
+    let input_ty = fcx.infcx().next_ty_var();
+    let return_ty = fcx.infcx().next_ty_var();
+
     // Try `IndexMut` first, if preferred.
     let method = match (lvalue_pref, fcx.tcx().lang_items.index_mut_trait()) {
         (PreferMutLvalue, Some(trait_did)) => {
-            method::lookup_in_trait(fcx,
-                                    expr.span,
-                                    Some(&*base_expr),
-                                    token::intern("index_mut"),
-                                    trait_did,
-                                    base_ty,
-                                    [])
+            method::lookup_in_trait_adjusted(fcx,
+                                             expr.span,
+                                             Some(&*base_expr),
+                                             token::intern("index_mut"),
+                                             trait_did,
+                                             adjustment.clone(),
+                                             adjusted_ty,
+                                             Some(vec![input_ty, return_ty]))
         }
         _ => None,
     };
@@ -2333,29 +2476,25 @@ fn try_overloaded_index(fcx: &FnCtxt,
     // Otherwise, fall back to `Index`.
     let method = match (method, fcx.tcx().lang_items.index_trait()) {
         (None, Some(trait_did)) => {
-            method::lookup_in_trait(fcx,
-                                    expr.span,
-                                    Some(&*base_expr),
-                                    token::intern("index"),
-                                    trait_did,
-                                    base_ty,
-                                    [])
+            method::lookup_in_trait_adjusted(fcx,
+                                             expr.span,
+                                             Some(&*base_expr),
+                                             token::intern("index"),
+                                             trait_did,
+                                             adjustment,
+                                             adjusted_ty,
+                                             Some(vec![input_ty, return_ty]))
         }
         (method, _) => method,
     };
 
-    // Regardless of whether the lookup succeeds, check the method arguments
-    // so that we have *some* type for each argument.
-    let method_type = get_method_ty(&method);
-    check_method_argument_types(fcx,
-                                expr.span,
-                                method_type,
-                                expr,
-                                &[index_expr],
-                                DoDerefArgs,
-                                DontTupleArguments);
-
-    make_return_type(fcx, method_call, method)
+    // If some lookup succeeds, write callee into table and extract index/element
+    // type from the method signature.
+    // If some lookup succeeded, install method in table
+    method.map(|method| {
+        make_overloaded_lvalue_return_type(fcx, Some(method_call), Some(method));
+        (input_ty, return_ty)
+    })
 }
 
 /// Given the head of a `for` expression, looks up the `next` method in the
@@ -2383,7 +2522,7 @@ fn lookup_method_for_for_loop(fcx: &FnCtxt,
                                          token::intern("next"),
                                          trait_did,
                                          expr_type,
-                                         []);
+                                         None);
 
     // Regardless of whether the lookup succeeds, check the method arguments
     // so that we have *some* type for each argument.
@@ -2427,10 +2566,15 @@ fn lookup_method_for_for_loop(fcx: &FnCtxt,
                         if !substs.types.is_empty_in(subst::TypeSpace) => {
                     *substs.types.get(subst::TypeSpace, 0)
                 }
+                ty::ty_err => {
+                    ty::mk_err()
+                }
                 _ => {
                     fcx.tcx().sess.span_err(iterator_expr.span,
-                                            "`next` method of the `Iterator` \
-                                             trait has an unexpected type");
+                                            format!("`next` method of the `Iterator` \
+                                                    trait has an unexpected type `{}`",
+                                                    fcx.infcx().ty_to_string(return_type))
+                                            .as_slice());
                     ty::mk_err()
                 }
             }
@@ -2457,7 +2601,7 @@ fn check_method_argument_types<'a>(fcx: &FnCtxt,
                              deref_args,
                              false,
                              tuple_arguments);
-        ty::FnConverging(method_fn_ty)
+        ty::FnConverging(ty::mk_err())
     } else {
         match ty::get(method_fn_ty).sty {
             ty::ty_bare_fn(ref fty) => {
@@ -3060,8 +3204,36 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                                   unbound_method: ||) -> ty::t {
         let method = match trait_did {
             Some(trait_did) => {
-                method::lookup_in_trait(fcx, op_ex.span, Some(lhs), opname,
-                                        trait_did, lhs_ty, &[])
+                // We do eager coercions to make using operators
+                // more ergonomic:
+                //
+                // - If the input is of type &'a T (resp. &'a mut T),
+                //   then reborrow it to &'b T (resp. &'b mut T) where
+                //   'b <= 'a.  This makes things like `x == y`, where
+                //   `x` and `y` are both region pointers, work.  We
+                //   could also solve this with variance or different
+                //   traits that don't force left and right to have same
+                //   type.
+                let (adj_ty, adjustment) = match ty::get(lhs_ty).sty {
+                    ty::ty_rptr(r_in, mt) => {
+                        let r_adj = fcx.infcx().next_region_var(infer::Autoref(lhs.span));
+                        fcx.mk_subr(infer::Reborrow(lhs.span), r_adj, r_in);
+                        let adjusted_ty = ty::mk_rptr(fcx.tcx(), r_adj, mt);
+                        let autoptr = ty::AutoPtr(r_adj, mt.mutbl, None);
+                        let adjustment = ty::AutoDerefRef { autoderefs: 1, autoref: Some(autoptr) };
+                        (adjusted_ty, adjustment)
+                    }
+                    _ => {
+                        (lhs_ty, ty::AutoDerefRef { autoderefs: 0, autoref: None })
+                    }
+                };
+
+                debug!("adjusted_ty={} adjustment={}",
+                       adj_ty.repr(fcx.tcx()),
+                       adjustment);
+
+                method::lookup_in_trait_adjusted(fcx, op_ex.span, Some(lhs), opname,
+                                                 trait_did, adjustment, adj_ty, None)
             }
             None => None
         };
@@ -4338,55 +4510,47 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
       ast::ExprIndex(ref base, ref idx) => {
           check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref);
           check_expr(fcx, &**idx);
-          let raw_base_t = fcx.expr_ty(&**base);
+          let base_t = fcx.expr_ty(&**base);
           let idx_t = fcx.expr_ty(&**idx);
-          if ty::type_is_error(raw_base_t) {
-              fcx.write_ty(id, raw_base_t);
+          if ty::type_is_error(base_t) {
+              fcx.write_ty(id, base_t);
           } else if ty::type_is_error(idx_t) {
               fcx.write_ty(id, idx_t);
           } else {
-              let (_, autoderefs, field_ty) =
-                autoderef(fcx, expr.span, raw_base_t, Some(base.id),
-                          lvalue_pref, |base_t, _| ty::index(base_t));
-              match field_ty {
-                  Some(ty) => {
-                      check_expr_has_type(fcx, &**idx, ty::mk_uint());
-                      fcx.write_ty(id, ty);
-                      fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
+              let base_t = structurally_resolved_type(fcx, expr.span, base_t);
+
+              let result =
+                  autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| {
+                      try_index_step(fcx,
+                                     MethodCall::expr(expr.id),
+                                     expr,
+                                     &**base,
+                                     adj_ty,
+                                     adj,
+                                     lvalue_pref)
+                  });
+
+              match result {
+                  Some((index_ty, element_ty)) => {
+                      check_expr_has_type(fcx, &**idx, index_ty);
+                      fcx.write_ty(id, element_ty);
                   }
                   _ => {
-                      // This is an overloaded method.
-                      let base_t = structurally_resolved_type(fcx,
-                                                              expr.span,
-                                                              raw_base_t);
-                      let method_call = MethodCall::expr(expr.id);
-                      match try_overloaded_index(fcx,
-                                                 Some(method_call),
-                                                 expr,
-                                                 &**base,
-                                                 base_t,
-                                                 idx,
-                                                 lvalue_pref) {
-                          Some(mt) => fcx.write_ty(id, mt.ty),
-                          None => {
-                                fcx.type_error_message(expr.span,
-                                                       |actual| {
-                                                        format!("cannot \
-                                                                 index a \
-                                                                 value of \
-                                                                 type `{}`",
-                                                                actual)
-                                                       },
-                                                       base_t,
-                                                       None);
-                                fcx.write_ty(id, ty::mk_err())
-                          }
-                      }
+                      check_expr_has_type(fcx, &**idx, ty::mk_err());
+                      fcx.type_error_message(
+                          expr.span,
+                          |actual| {
+                              format!("cannot index a value of type `{}`",
+                                      actual)
+                          },
+                          base_t,
+                          None);
+                      fcx.write_ty(id, ty::mk_err())
                   }
               }
           }
        }
-       ast::ExprSlice(ref base, ref start, ref end, ref mutbl) => {
+       ast::ExprSlice(ref base, ref start, ref end, mutbl) => {
           check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref);
           let raw_base_t = fcx.expr_ty(&**base);
 
@@ -4415,19 +4579,19 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
                                                       raw_base_t);
               let method_call = MethodCall::expr(expr.id);
               match try_overloaded_slice(fcx,
-                                         Some(method_call),
+                                         method_call,
                                          expr,
                                          &**base,
                                          base_t,
                                          start,
                                          end,
                                          mutbl) {
-                  Some(mt) => fcx.write_ty(id, mt.ty),
+                  Some(ty) => fcx.write_ty(id, ty),
                   None => {
                         fcx.type_error_message(expr.span,
                            |actual| {
                                 format!("cannot take a {}slice of a value with type `{}`",
-                                        if mutbl == &ast::MutMutable {
+                                        if mutbl == ast::MutMutable {
                                             "mutable "
                                         } else {
                                             ""
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index fb80b9f30f5..91e563c75e4 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -32,6 +32,7 @@ use syntax::ast_map;
 use syntax::codemap::{Span, Pos};
 use syntax::parse::token;
 use syntax::print::pprust;
+use syntax::ptr::P;
 use syntax::{ast, ast_util};
 use syntax::owned_slice::OwnedSlice;
 
@@ -561,6 +562,12 @@ impl<T:Repr> Repr for Option<T> {
     }
 }
 
+impl<T:Repr> Repr for P<T> {
+    fn repr(&self, tcx: &ctxt) -> String {
+        (*self).repr(tcx)
+    }
+}
+
 impl<T:Repr,U:Repr> Repr for Result<T,U> {
     fn repr(&self, tcx: &ctxt) -> String {
         match self {
diff --git a/src/test/compile-fail/borrowck-overloaded-index-autoderef.rs b/src/test/compile-fail/borrowck-overloaded-index-autoderef.rs
new file mode 100644
index 00000000000..2253d7512c0
--- /dev/null
+++ b/src/test/compile-fail/borrowck-overloaded-index-autoderef.rs
@@ -0,0 +1,91 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we still see borrowck errors of various kinds when using
+// indexing and autoderef in combination.
+
+struct Foo {
+    x: int,
+    y: int,
+}
+
+impl Index<String,int> for Foo {
+    fn index<'a>(&'a self, z: &String) -> &'a int {
+        if z.as_slice() == "x" {
+            &self.x
+        } else {
+            &self.y
+        }
+    }
+}
+
+impl IndexMut<String,int> for Foo {
+    fn index_mut<'a>(&'a mut self, z: &String) -> &'a mut int {
+        if z.as_slice() == "x" {
+            &mut self.x
+        } else {
+            &mut self.y
+        }
+    }
+}
+
+fn test1(mut f: Box<Foo>, s: String) {
+    let _p = &mut f[s];
+    let _q = &f[s]; //~ ERROR cannot borrow
+}
+
+fn test2(mut f: Box<Foo>, s: String) {
+    let _p = &mut f[s];
+    let _q = &mut f[s]; //~ ERROR cannot borrow
+}
+
+struct Bar {
+    foo: Foo
+}
+
+fn test3(mut f: Box<Bar>, s: String) {
+    let _p = &mut f.foo[s];
+    let _q = &mut f.foo[s]; //~ ERROR cannot borrow
+}
+
+fn test4(mut f: Box<Bar>, s: String) {
+    let _p = &f.foo[s];
+    let _q = &f.foo[s];
+}
+
+fn test5(mut f: Box<Bar>, s: String) {
+    let _p = &f.foo[s];
+    let _q = &mut f.foo[s]; //~ ERROR cannot borrow
+}
+
+fn test6(mut f: Box<Bar>, g: Foo, s: String) {
+    let _p = &f.foo[s];
+    f.foo = g; //~ ERROR cannot assign
+}
+
+fn test7(mut f: Box<Bar>, g: Bar, s: String) {
+    let _p = &f.foo[s];
+    *f = g; //~ ERROR cannot assign
+}
+
+fn test8(mut f: Box<Bar>, g: Foo, s: String) {
+    let _p = &mut f.foo[s];
+    f.foo = g; //~ ERROR cannot assign
+}
+
+fn test9(mut f: Box<Bar>, g: Bar, s: String) {
+    let _p = &mut f.foo[s];
+    *f = g; //~ ERROR cannot assign
+}
+
+fn main() {
+}
+
+
diff --git a/src/test/compile-fail/issue-13482-2.rs b/src/test/compile-fail/issue-13482-2.rs
index 6746b90e32d..4ec8c2b1b7e 100644
--- a/src/test/compile-fail/issue-13482-2.rs
+++ b/src/test/compile-fail/issue-13482-2.rs
@@ -14,7 +14,7 @@ fn main() {
     let x = [1,2];
     let y = match x {
         [] => None,
-        //~^ ERROR types: expected `[_#0i, ..2]`, found `[_#7, ..0]`
+        //~^ ERROR types: expected `[_#0i, ..2]`, found `[_#7t, ..0]`
         //         (expected array of 2 elements, found array of 0 elements)
         [a,_] => Some(a)
     };
diff --git a/src/test/compile-fail/issue-15207.rs b/src/test/compile-fail/issue-15207.rs
index 37fcabef0ed..61877775269 100644
--- a/src/test/compile-fail/issue-15207.rs
+++ b/src/test/compile-fail/issue-15207.rs
@@ -11,7 +11,6 @@
 fn main() {
     loop {
         break.push(1) //~ ERROR the type of this value must be known in this context
-        //~^ ERROR multiple applicable methods in scope
         ;
     }
 }
diff --git a/src/test/compile-fail/issue-17033.rs b/src/test/compile-fail/issue-17033.rs
index 7590546d40a..5048a9aa919 100644
--- a/src/test/compile-fail/issue-17033.rs
+++ b/src/test/compile-fail/issue-17033.rs
@@ -11,7 +11,7 @@
 #![feature(overloaded_calls)]
 
 fn f<'r>(p: &'r mut fn(p: &mut ())) {
-    p(()) //~ ERROR mismatched types: expected `&mut ()`, found `()`
+    (*p)(()) //~ ERROR mismatched types: expected `&mut ()`, found `()`
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs
index e64d674b7c8..1150f40db76 100644
--- a/src/test/compile-fail/issue-2149.rs
+++ b/src/test/compile-fail/issue-2149.rs
@@ -18,7 +18,6 @@ impl<A> vec_monad<A> for Vec<A> {
         let mut r = panic!();
         for elt in self.iter() { r = r + f(*elt); }
         //~^ ERROR the type of this value must be known
-        //~^^ ERROR not implemented
    }
 }
 fn main() {
diff --git a/src/test/compile-fail/slice-mut-2.rs b/src/test/compile-fail/slice-mut-2.rs
index 09019448a67..6778ed88ff7 100644
--- a/src/test/compile-fail/slice-mut-2.rs
+++ b/src/test/compile-fail/slice-mut-2.rs
@@ -15,5 +15,5 @@
 fn main() {
     let x: &[int] = &[1, 2, 3, 4, 5];
     // Can't mutably slice an immutable slice
-    let y = x[mut 2..4]; //~ ERROR cannot take a mutable slice of a value with type `&[int]`
+    let y = x[mut 2..4]; //~ ERROR cannot borrow
 }
diff --git a/src/test/compile-fail/type-params-in-different-spaces-1.rs b/src/test/compile-fail/type-params-in-different-spaces-1.rs
index 6e32e6e4835..c87e8541758 100644
--- a/src/test/compile-fail/type-params-in-different-spaces-1.rs
+++ b/src/test/compile-fail/type-params-in-different-spaces-1.rs
@@ -12,7 +12,7 @@ use std::num::Num;
 
 trait BrokenAdd: Num {
     fn broken_add<T>(&self, rhs: T) -> Self {
-        *self + rhs //~ ERROR mismatched types
+        *self + rhs //~ ERROR expected `Self`, found `T`
     }
 }
 
diff --git a/src/test/run-pass/overload-index-operator.rs b/src/test/run-pass/overloaded-index-assoc-list.rs
index 7c6ad45a9ef..7c6ad45a9ef 100644
--- a/src/test/run-pass/overload-index-operator.rs
+++ b/src/test/run-pass/overloaded-index-assoc-list.rs
diff --git a/src/test/run-pass/overloaded-index-autoderef.rs b/src/test/run-pass/overloaded-index-autoderef.rs
new file mode 100644
index 00000000000..d51956da894
--- /dev/null
+++ b/src/test/run-pass/overloaded-index-autoderef.rs
@@ -0,0 +1,79 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test overloaded indexing combined with autoderef.
+
+struct Foo {
+    x: int,
+    y: int,
+}
+
+impl Index<int,int> for Foo {
+    fn index(&self, z: &int) -> &int {
+        if *z == 0 {
+            &self.x
+        } else {
+            &self.y
+        }
+    }
+}
+
+impl IndexMut<int,int> for Foo {
+    fn index_mut(&mut self, z: &int) -> &mut int {
+        if *z == 0 {
+            &mut self.x
+        } else {
+            &mut self.y
+        }
+    }
+}
+
+trait Int {
+    fn get(self) -> int;
+    fn get_from_ref(&self) -> int;
+    fn inc(&mut self);
+}
+
+impl Int for int {
+    fn get(self) -> int { self }
+    fn get_from_ref(&self) -> int { *self }
+    fn inc(&mut self) { *self += 1; }
+}
+
+fn main() {
+    let mut f = box Foo {
+        x: 1,
+        y: 2,
+    };
+
+    assert_eq!(f[1], 2);
+
+    f[0] = 3;
+
+    assert_eq!(f[0], 3);
+
+    // Test explicit IndexMut where `f` must be autoderef:
+    {
+        let p = &mut f[1];
+        *p = 4;
+    }
+
+    // Test explicit Index where `f` must be autoderef:
+    {
+        let p = &f[1];
+        assert_eq!(*p, 4);
+    }
+
+    // Test calling methods with `&mut self`, `self, and `&self` receivers:
+    f[1].inc();
+    assert_eq!(f[1].get(), 5);
+    assert_eq!(f[1].get_from_ref(), 5);
+}
+
diff --git a/src/test/run-pass/overloaded-index-in-field.rs b/src/test/run-pass/overloaded-index-in-field.rs
new file mode 100644
index 00000000000..e8b0408ca0d
--- /dev/null
+++ b/src/test/run-pass/overloaded-index-in-field.rs
@@ -0,0 +1,52 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test using overloaded indexing when the "map" is stored in a
+// field. This caused problems at some point.
+
+struct Foo {
+    x: int,
+    y: int,
+}
+
+struct Bar {
+    foo: Foo
+}
+
+impl Index<int,int> for Foo {
+    fn index(&self, z: &int) -> &int {
+        if *z == 0 {
+            &self.x
+        } else {
+            &self.y
+        }
+    }
+}
+
+trait Int {
+    fn get(self) -> int;
+    fn get_from_ref(&self) -> int;
+    fn inc(&mut self);
+}
+
+impl Int for int {
+    fn get(self) -> int { self }
+    fn get_from_ref(&self) -> int { *self }
+    fn inc(&mut self) { *self += 1; }
+}
+
+fn main() {
+    let f = Bar { foo: Foo {
+        x: 1,
+        y: 2,
+    } };
+    assert_eq!(f.foo[1].get(), 2);
+}
+
diff --git a/src/test/run-pass/overloaded-index.rs b/src/test/run-pass/overloaded-index.rs
index 1187e066950..23bebfa35d7 100644
--- a/src/test/run-pass/overloaded-index.rs
+++ b/src/test/run-pass/overloaded-index.rs
@@ -33,6 +33,18 @@ impl IndexMut<int,int> for Foo {
     }
 }
 
+trait Int {
+    fn get(self) -> int;
+    fn get_from_ref(&self) -> int;
+    fn inc(&mut self);
+}
+
+impl Int for int {
+    fn get(self) -> int { self }
+    fn get_from_ref(&self) -> int { *self }
+    fn inc(&mut self) { *self += 1; }
+}
+
 fn main() {
     let mut f = Foo {
         x: 1,
@@ -49,5 +61,10 @@ fn main() {
         let p = &f[1];
         assert_eq!(*p, 4);
     }
+
+    // Test calling methods with `&mut self`, `self, and `&self` receivers:
+    f[1].inc();
+    assert_eq!(f[1].get(), 5);
+    assert_eq!(f[1].get_from_ref(), 5);
 }