about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/doc/guide.md10
-rw-r--r--src/libarena/lib.rs2
-rw-r--r--src/libcollections/slice.rs14
-rw-r--r--src/libcollections/vec.rs8
-rw-r--r--src/libcore/array.rs83
-rw-r--r--src/libcore/lib.rs4
-rw-r--r--src/libcore/option.rs4
-rw-r--r--src/libcore/result.rs4
-rw-r--r--src/libcoretest/iter.rs8
-rw-r--r--src/librustc/middle/ty.rs23
-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/middle/typeck/infer/region_inference/mod.rs12
-rw-r--r--src/librustc/util/ppaux.rs21
-rw-r--r--src/libstd/bitflags.rs4
-rw-r--r--src/libstd/collections/hash/set.rs2
-rw-r--r--src/libstd/time/duration.rs2
-rw-r--r--src/libtime/lib.rs2
-rw-r--r--src/test/bench/shootout-meteor.rs2
-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/operator-multidispatch.rs41
-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
31 files changed, 1009 insertions, 263 deletions
diff --git a/src/doc/guide.md b/src/doc/guide.md
index 8493a30a16e..9a1a42478d3 100644
--- a/src/doc/guide.md
+++ b/src/doc/guide.md
@@ -4601,20 +4601,24 @@ returns `true` or `false`. The new iterator `filter()` produces
 only the elements that that closure returns `true` for:
 
 ```{rust}
-for i in range(1i, 100i).filter(|x| x % 2 == 0) {
+for i in range(1i, 100i).filter(|&x| x % 2 == 0) {
     println!("{}", i);
 }
 ```
 
 This will print all of the even numbers between one and a hundred.
+(Note that because `filter` doesn't consume the elements that are
+being iterated over, it is passed a reference to each element, and
+thus the filter predicate uses the `&x` pattern to extract the integer
+itself.)
 
 You can chain all three things together: start with an iterator, adapt it
 a few times, and then consume the result. Check it out:
 
 ```{rust}
 range(1i, 1000i)
-    .filter(|x| x % 2 == 0)
-    .filter(|x| x % 3 == 0)
+    .filter(|&x| x % 2 == 0)
+    .filter(|&x| x % 3 == 0)
     .take(5)
     .collect::<Vec<int>>();
 ```
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 415b12c7d05..3e93430eb69 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -132,7 +132,7 @@ impl Drop for Arena {
 
 #[inline]
 fn round_up(base: uint, align: uint) -> uint {
-    (base.checked_add(&(align - 1))).unwrap() & !(&(align - 1))
+    (base.checked_add(&(align - 1))).unwrap() & !(align - 1)
 }
 
 // Walk down a chunk, running the destructors for any objects stored
diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index 107dc3e5c28..eb4ff345b51 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -1598,15 +1598,15 @@ mod tests {
     #[test]
     fn test_total_ord() {
         let c: &[int] = &[1, 2, 3];
-        [1, 2, 3, 4].cmp(& c) == Greater;
+        [1, 2, 3, 4][].cmp(& c) == Greater;
         let c: &[int] = &[1, 2, 3, 4];
-        [1, 2, 3].cmp(& c) == Less;
+        [1, 2, 3][].cmp(& c) == Less;
         let c: &[int] = &[1, 2, 3, 6];
-        [1, 2, 3, 4].cmp(& c) == Equal;
+        [1, 2, 3, 4][].cmp(& c) == Equal;
         let c: &[int] = &[1, 2, 3, 4, 5, 6];
-        [1, 2, 3, 4, 5, 5, 5, 5].cmp(& c) == Less;
+        [1, 2, 3, 4, 5, 5, 5, 5][].cmp(& c) == Less;
         let c: &[int] = &[1, 2, 3, 4];
-        [2, 2].cmp(& c) == Greater;
+        [2, 2][].cmp(& c) == Greater;
     }
 
     #[test]
@@ -1980,7 +1980,7 @@ mod tests {
             let (left, right) = values.split_at_mut(2);
             {
                 let left: &[_] = left;
-                assert!(left[0..left.len()] == [1, 2]);
+                assert!(left[0..left.len()] == [1, 2][]);
             }
             for p in left.iter_mut() {
                 *p += 1;
@@ -1988,7 +1988,7 @@ mod tests {
 
             {
                 let right: &[_] = right;
-                assert!(right[0..right.len()] == [3, 4, 5]);
+                assert!(right[0..right.len()] == [3, 4, 5][]);
             }
             for p in right.iter_mut() {
                 *p += 2;
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index f9f4ae534c1..40e7c949972 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -919,7 +919,7 @@ impl<T> Vec<T> {
     ///
     /// ```
     /// let mut vec = vec![1i, 2, 3, 4];
-    /// vec.retain(|x| x%2 == 0);
+    /// vec.retain(|&x| x%2 == 0);
     /// assert_eq!(vec, vec![2, 4]);
     /// ```
     #[unstable = "the closure argument may become an unboxed closure"]
@@ -1800,7 +1800,7 @@ mod tests {
             let (left, right) = values.split_at_mut(2);
             {
                 let left: &[_] = left;
-                assert!(left[0..left.len()] == [1, 2]);
+                assert!(left[0..left.len()] == [1, 2][]);
             }
             for p in left.iter_mut() {
                 *p += 1;
@@ -1808,7 +1808,7 @@ mod tests {
 
             {
                 let right: &[_] = right;
-                assert!(right[0..right.len()] == [3, 4, 5]);
+                assert!(right[0..right.len()] == [3, 4, 5][]);
             }
             for p in right.iter_mut() {
                 *p += 2;
@@ -1863,7 +1863,7 @@ mod tests {
     #[test]
     fn test_retain() {
         let mut vec = vec![1u, 2, 3, 4];
-        vec.retain(|x| x%2 == 0);
+        vec.retain(|&x| x % 2 == 0);
         assert!(vec == vec![2u, 4]);
     }
 
diff --git a/src/libcore/array.rs b/src/libcore/array.rs
new file mode 100644
index 00000000000..829605ce7cc
--- /dev/null
+++ b/src/libcore/array.rs
@@ -0,0 +1,83 @@
+// 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.
+
+/*!
+ * Implementations of things like `Eq` for fixed-length arrays
+ * up to a certain length. Eventually we should able to generalize
+ * to all lengths.
+ */
+
+#![stable]
+#![experimental] // not yet reviewed
+
+use cmp::*;
+use option::{Option};
+
+// macro for implementing n-ary tuple functions and operations
+macro_rules! array_impls {
+    ($($N:expr)+) => {
+        $(
+            #[unstable = "waiting for PartialEq to stabilize"]
+            impl<T:PartialEq> PartialEq for [T, ..$N] {
+                #[inline]
+                fn eq(&self, other: &[T, ..$N]) -> bool {
+                    self[] == other[]
+                }
+                #[inline]
+                fn ne(&self, other: &[T, ..$N]) -> bool {
+                    self[] != other[]
+                }
+            }
+
+            #[unstable = "waiting for Eq to stabilize"]
+            impl<T:Eq> Eq for [T, ..$N] { }
+
+            #[unstable = "waiting for PartialOrd to stabilize"]
+            impl<T:PartialOrd> PartialOrd for [T, ..$N] {
+                #[inline]
+                fn partial_cmp(&self, other: &[T, ..$N]) -> Option<Ordering> {
+                    PartialOrd::partial_cmp(&self[], &other[])
+                }
+                #[inline]
+                fn lt(&self, other: &[T, ..$N]) -> bool {
+                    PartialOrd::lt(&self[], &other[])
+                }
+                #[inline]
+                fn le(&self, other: &[T, ..$N]) -> bool {
+                    PartialOrd::le(&self[], &other[])
+                }
+                #[inline]
+                fn ge(&self, other: &[T, ..$N]) -> bool {
+                    PartialOrd::ge(&self[], &other[])
+                }
+                #[inline]
+                fn gt(&self, other: &[T, ..$N]) -> bool {
+                    PartialOrd::gt(&self[], &other[])
+                }
+            }
+
+            #[unstable = "waiting for Ord to stabilize"]
+            impl<T:Ord> Ord for [T, ..$N] {
+                #[inline]
+                fn cmp(&self, other: &[T, ..$N]) -> Ordering {
+                    Ord::cmp(&self[], &other[])
+                }
+            }
+        )+
+    }
+}
+
+array_impls! {
+     0  1  2  3  4  5  6  7  8  9
+    10 11 12 13 14 15 16 17 18 19
+    20 21 22 23 24 25 26 27 28 29
+    30 31 32
+}
+
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 7c5c54c6d8a..d9a0c398605 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -126,6 +126,10 @@ pub mod tuple;
 pub mod unit;
 pub mod fmt;
 
+// note: does not need to be public
+#[cfg(not(stage0))]
+mod array;
+
 #[doc(hidden)]
 mod core {
     pub use panicking;
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 522eb833637..b787de4423a 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -787,8 +787,8 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
     /// use std::uint;
     ///
     /// let v = vec!(1u, 2u);
-    /// let res: Option<Vec<uint>> = v.iter().map(|x: &uint|
-    ///     if *x == uint::MAX { None }
+    /// let res: Option<Vec<uint>> = v.iter().map(|&x: &uint|
+    ///     if x == uint::MAX { None }
     ///     else { Some(x + 1) }
     /// ).collect();
     /// assert!(res == Some(vec!(2u, 3u)));
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 5b75e98baef..2ad5521bb76 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -894,8 +894,8 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
     /// use std::uint;
     ///
     /// let v = vec!(1u, 2u);
-    /// let res: Result<Vec<uint>, &'static str> = v.iter().map(|x: &uint|
-    ///     if *x == uint::MAX { Err("Overflow!") }
+    /// let res: Result<Vec<uint>, &'static str> = v.iter().map(|&x: &uint|
+    ///     if x == uint::MAX { Err("Overflow!") }
     ///     else { Ok(x + 1) }
     /// ).collect();
     /// assert!(res == Ok(vec!(2u, 3u)));
diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs
index 5d333d48e96..aeab18ca05e 100644
--- a/src/libcoretest/iter.rs
+++ b/src/libcoretest/iter.rs
@@ -356,7 +356,7 @@ fn test_iterator_size_hint() {
     assert_eq!(vi.zip(v2.iter()).size_hint(), (3, Some(3)));
     assert_eq!(vi.scan(0i, |_,_| Some(0i)).size_hint(), (0, Some(10)));
     assert_eq!(vi.filter(|_| false).size_hint(), (0, Some(10)));
-    assert_eq!(vi.map(|i| i+1).size_hint(), (10, Some(10)));
+    assert_eq!(vi.map(|&i| i+1).size_hint(), (10, Some(10)));
     assert_eq!(vi.filter_map(|_| Some(0i)).size_hint(), (0, Some(10)));
 }
 
@@ -388,9 +388,9 @@ fn test_any() {
 #[test]
 fn test_find() {
     let v: &[int] = &[1i, 3, 9, 27, 103, 14, 11];
-    assert_eq!(*v.iter().find(|x| *x & 1 == 0).unwrap(), 14);
-    assert_eq!(*v.iter().find(|x| *x % 3 == 0).unwrap(), 3);
-    assert!(v.iter().find(|x| *x % 12 == 0).is_none());
+    assert_eq!(*v.iter().find(|&&x| x & 1 == 0).unwrap(), 14);
+    assert_eq!(*v.iter().find(|&&x| x % 3 == 0).unwrap(), 3);
+    assert!(v.iter().find(|&&x| x % 12 == 0).is_none());
 }
 
 #[test]
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index bdb9ef8e710..76caa42b850 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -1167,25 +1167,25 @@ impl cmp::PartialEq for InferRegion {
 
 impl fmt::Show for TyVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
-        write!(f, "<generic #{}>", self.index)
+        write!(f, "_#{}t", self.index)
     }
 }
 
 impl fmt::Show for IntVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "<generic integer #{}>", self.index)
+        write!(f, "_#{}i", self.index)
     }
 }
 
 impl fmt::Show for FloatVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "<generic float #{}>", self.index)
+        write!(f, "_#{}f", self.index)
     }
 }
 
 impl fmt::Show for RegionVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "'<generic lifetime #{}>", self.index)
+        write!(f, "'_#{}r", self.index)
     }
 }
 
@@ -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/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs
index ff1ded726c5..cdc45890c09 100644
--- a/src/librustc/middle/typeck/infer/region_inference/mod.rs
+++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs
@@ -952,6 +952,11 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                              -> Vec<VarValue>
     {
         let mut var_data = self.construct_var_data();
+
+        // Dorky hack to cause `dump_constraints` to only get called
+        // if debug mode is enabled:
+        debug!("----() End constraint listing {}---", self.dump_constraints());
+
         self.expansion(var_data.as_mut_slice());
         self.contraction(var_data.as_mut_slice());
         let values =
@@ -974,6 +979,13 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         })
     }
 
+    fn dump_constraints(&self) {
+        debug!("----() Start constraint listing ()----");
+        for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() {
+            debug!("Constraint {} => {}", idx, constraint.repr(self.tcx));
+        }
+    }
+
     fn expansion(&self, var_data: &mut [VarData]) {
         self.iterate_until_fixed_point("Expansion", |constraint| {
             debug!("expansion: constraint={} origin={}",
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index fb80b9f30f5..33e14197532 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;
 
@@ -372,14 +373,10 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
     fn infer_ty_to_string(cx: &ctxt, ty: ty::InferTy) -> String {
         let print_var_ids = cx.sess.verbose();
         match ty {
-            ty::TyVar(ty::TyVid { index: vid }) if print_var_ids =>
-                format!("_#{}", vid),
-            ty::IntVar(ty::IntVid { index: vid }) if print_var_ids =>
-                format!("_#{}i", vid),
-            ty::FloatVar(ty::FloatVid { index: vid }) if print_var_ids =>
-                format!("_#{}f", vid),
-            ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) =>
-                "_".to_string(),
+            ty::TyVar(ref vid) if print_var_ids => vid.repr(cx),
+            ty::IntVar(ref vid) if print_var_ids => vid.repr(cx),
+            ty::FloatVar(ref vid) if print_var_ids => vid.repr(cx),
+            ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => format!("_"),
             ty::SkolemizedTy(v) => format!("SkolemizedTy({})", v),
             ty::SkolemizedIntTy(v) => format!("SkolemizedIntTy({})", v)
         }
@@ -561,6 +558,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 {
@@ -851,7 +854,7 @@ impl Repr for ty::Region {
             }
 
             ty::ReInfer(ReVar(ref vid)) => {
-                format!("ReInfer({})", vid.index)
+                format!("{}", vid)
             }
 
             ty::ReInfer(ReSkolemized(id, ref bound_region)) => {
diff --git a/src/libstd/bitflags.rs b/src/libstd/bitflags.rs
index 97a1f68606f..d8023dd3e4e 100644
--- a/src/libstd/bitflags.rs
+++ b/src/libstd/bitflags.rs
@@ -177,13 +177,13 @@ macro_rules! bitflags {
             /// Returns `true` if there are flags common to both `self` and `other`.
             #[inline]
             pub fn intersects(&self, other: $BitFlags) -> bool {
-                !(self & other).is_empty()
+                !(*self & other).is_empty()
             }
 
             /// Returns `true` all of the flags in `other` are contained within `self`.
             #[inline]
             pub fn contains(&self, other: $BitFlags) -> bool {
-                (self & other) == other
+                (*self & other) == other
             }
 
             /// Inserts the specified flags in-place.
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index b9758e11bc7..688036d22dd 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -792,7 +792,7 @@ mod test_set {
         };
 
         let v = hs.into_iter().collect::<Vec<char>>();
-        assert!(['a', 'b'] == v.as_slice() || ['b', 'a'] == v.as_slice());
+        assert!(['a', 'b'][] == v.as_slice() || ['b', 'a'][] == v.as_slice());
     }
 
     #[test]
diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs
index 102f0028557..c3adae8cff8 100644
--- a/src/libstd/time/duration.rs
+++ b/src/libstd/time/duration.rs
@@ -319,7 +319,7 @@ impl fmt::Show for Duration {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // technically speaking, negative duration is not valid ISO 8601,
         // but we need to print it anyway.
-        let (abs, sign) = if self.secs < 0 { (-self, "-") } else { (*self, "") };
+        let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
 
         let days = abs.secs / SECS_PER_DAY;
         let secs = abs.secs - days * SECS_PER_DAY;
diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs
index 590d0bfdcab..ac3574f5a03 100644
--- a/src/libtime/lib.rs
+++ b/src/libtime/lib.rs
@@ -96,7 +96,7 @@ impl Add<Duration, Timespec> for Timespec {
         let d_sec = other.num_seconds();
         // It is safe to unwrap the nanoseconds, because there cannot be
         // more than one second left, which fits in i64 and in i32.
-        let d_nsec = (other - Duration::seconds(d_sec))
+        let d_nsec = (*other - Duration::seconds(d_sec))
                      .num_nanoseconds().unwrap() as i32;
         let mut sec = self.sec + d_sec;
         let mut nsec = self.nsec + d_nsec;
diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs
index 6e80c07a1a2..47e1969172d 100644
--- a/src/test/bench/shootout-meteor.rs
+++ b/src/test/bench/shootout-meteor.rs
@@ -290,7 +290,7 @@ fn search(
     let masks_at = &masks[i];
 
     // for every unused piece
-    for id in range(0u, 10).filter(|id| board & (1 << (id + 50)) == 0) {
+    for id in range(0u, 10).filter(|&id| board & (1 << (id + 50)) == 0) {
         // for each mask that fits on the board
         for m in masks_at[id].iter().filter(|&m| board & *m == 0) {
             // This check is too costly.
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/operator-multidispatch.rs b/src/test/run-pass/operator-multidispatch.rs
new file mode 100644
index 00000000000..fc79e4f0edb
--- /dev/null
+++ b/src/test/run-pass/operator-multidispatch.rs
@@ -0,0 +1,41 @@
+// 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 can overload the `+` operator for points so that two
+// points can be added, and a point can be added to an integer.
+
+use std::ops;
+
+#[deriving(Show,PartialEq,Eq)]
+struct Point {
+    x: int,
+    y: int
+}
+
+impl ops::Add<Point,Point> for Point {
+    fn add(&self, other: &Point) -> Point {
+        Point {x: self.x + (*other).x, y: self.y + (*other).y}
+    }
+}
+
+impl ops::Add<int,Point> for Point {
+    fn add(&self, &other: &int) -> Point {
+        Point {x: self.x + other,
+               y: self.y + other}
+    }
+}
+
+pub fn main() {
+    let mut p = Point {x: 10, y: 20};
+    p = p + Point {x: 101, y: 102};
+    assert_eq!(p, Point {x: 111, y: 122});
+    p = p + 1;
+    assert_eq!(p, Point {x: 112, y: 123});
+}
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);
 }