about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-04-08 09:58:05 +0000
committerbors <bors@rust-lang.org>2015-04-08 09:58:05 +0000
commit926f38e588bb99aff1902fa94ab82b1db89cbbce (patch)
treec1551948b685c3a8797592727c01b921a118beac
parent3a66c7f6263ca390436a6faa9b8cbd0ef66c1e6c (diff)
parent63b36ea7c211406a76c34cba5ac9b7218e003757 (diff)
downloadrust-926f38e588bb99aff1902fa94ab82b1db89cbbce.tar.gz
rust-926f38e588bb99aff1902fa94ab82b1db89cbbce.zip
Auto merge of #23998 - nrc:impl-self, r=nikomatsakis
Closes #23909

r? @nikomatsakis (or anyone else, really)
-rw-r--r--src/librustc/middle/astencode.rs6
-rw-r--r--src/librustc/middle/def.rs12
-rw-r--r--src/librustc_privacy/lib.rs2
-rw-r--r--src/librustc_resolve/lib.rs169
-rw-r--r--src/librustc_trans/save/mod.rs2
-rw-r--r--src/librustc_typeck/astconv.rs295
-rw-r--r--src/librustc_typeck/check/mod.rs16
-rw-r--r--src/librustc_typeck/collect.rs19
-rw-r--r--src/libsyntax/ext/expand.rs43
-rw-r--r--src/test/compile-fail/self-impl.rs40
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs2
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs2
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs2
-rw-r--r--src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs2
-rw-r--r--src/test/run-pass/self-impl.rs40
15 files changed, 399 insertions, 253 deletions
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index b6061f39233..998ce0cac47 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -457,7 +457,11 @@ impl tr for def::Def {
           def::DefMethod(did, p) => {
             def::DefMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx)))
           }
-          def::DefSelfTy(nid) => { def::DefSelfTy(dcx.tr_id(nid)) }
+          def::DefSelfTy(opt_did, impl_ids) => { def::DefSelfTy(opt_did.map(|did| did.tr(dcx)),
+                                                                impl_ids.map(|(nid1, nid2)| {
+                                                                    (dcx.tr_id(nid1),
+                                                                     dcx.tr_id(nid2))
+                                                                })) }
           def::DefMod(did) => { def::DefMod(did.tr(dcx)) }
           def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
           def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs
index 6707a4d3fd7..f0b35908854 100644
--- a/src/librustc/middle/def.rs
+++ b/src/librustc/middle/def.rs
@@ -22,7 +22,8 @@ use std::cell::RefCell;
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Def {
     DefFn(ast::DefId, bool /* is_ctor */),
-    DefSelfTy(/* trait id */ ast::NodeId),
+    DefSelfTy(Option<ast::DefId>,                    // trait id
+              Option<(ast::NodeId, ast::NodeId)>),   // (impl id, self type id)
     DefMod(ast::DefId),
     DefForeignMod(ast::DefId),
     DefStatic(ast::DefId, bool /* is_mutbl */),
@@ -139,18 +140,19 @@ impl Def {
             DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
             DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
             DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
-            DefMethod(id, _) | DefConst(id) => {
+            DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> {
                 id
             }
             DefLocal(id) |
-            DefSelfTy(id) |
             DefUpvar(id, _) |
             DefRegion(id) |
-            DefLabel(id) => {
+            DefLabel(id)  |
+            DefSelfTy(_, Some((_, id))) => {
                 local_def(id)
             }
 
-            DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy")
+            DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy"),
+            DefSelfTy(..) => panic!("attempted .def_id() on invalid DefSelfTy"),
         }
     }
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 1acc121078e..2884cebf666 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -1178,7 +1178,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
         let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
             // `int` etc. (None doesn't seem to occur.)
             None | Some(def::DefPrimTy(..)) => return false,
-            Some(def) => def.def_id()
+            Some(def) => def.def_id(),
         };
         // A path can only be private if:
         // it's in this crate...
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 045320e4fa4..f90c7640f8c 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1689,7 +1689,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                 }
             }
-            DefTyParam(..) | DefSelfTy(_) => {
+            DefTyParam(..) | DefSelfTy(..) => {
                 for rib in ribs {
                     match rib.kind {
                         NormalRibKind | MethodRibKind | ClosureRibKind(..) => {
@@ -1797,63 +1797,57 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
 
             ItemDefaultImpl(_, ref trait_ref) => {
-                self.with_optional_trait_ref(Some(trait_ref), |_| {});
+                self.with_optional_trait_ref(Some(trait_ref), |_, _| {});
             }
-            ItemImpl(_, _,
+            ItemImpl(_,
+                     _,
                      ref generics,
-                     ref implemented_traits,
+                     ref opt_trait_ref,
                      ref self_type,
                      ref impl_items) => {
                 self.resolve_implementation(generics,
-                                            implemented_traits,
+                                            opt_trait_ref,
                                             &**self_type,
+                                            item.id,
                                             &impl_items[..]);
             }
 
             ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
                 self.check_if_primitive_type_name(name, item.span);
 
-                // Create a new rib for the self type.
-                let mut self_type_rib = Rib::new(ItemRibKind);
-
-                // plain insert (no renaming, types are not currently hygienic....)
-                let name = special_names::type_self;
-                self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id)));
-                self.type_ribs.push(self_type_rib);
-
                 // Create a new rib for the trait-wide type parameters.
                 self.with_type_parameter_rib(HasTypeParameters(generics,
                                                                TypeSpace,
-                                                               NormalRibKind),
+                                                               ItemRibKind),
                                              |this| {
-                    this.visit_generics(generics);
-                    visit::walk_ty_param_bounds_helper(this, bounds);
-
-                    for trait_item in trait_items {
-                        // Create a new rib for the trait_item-specific type
-                        // parameters.
-                        //
-                        // FIXME #4951: Do we need a node ID here?
-
-                        let type_parameters = match trait_item.node {
-                            ast::MethodTraitItem(ref sig, _) => {
-                                HasTypeParameters(&sig.generics,
-                                                  FnSpace,
-                                                  MethodRibKind)
-                            }
-                            ast::TypeTraitItem(..) => {
-                                this.check_if_primitive_type_name(trait_item.ident.name,
-                                                                  trait_item.span);
-                                NoTypeParameters
-                            }
-                        };
-                        this.with_type_parameter_rib(type_parameters, |this| {
-                            visit::walk_trait_item(this, trait_item)
-                        });
-                    }
+                    this.with_self_rib(DefSelfTy(Some(local_def(item.id)), None), |this| {
+                        this.visit_generics(generics);
+                        visit::walk_ty_param_bounds_helper(this, bounds);
+
+                        for trait_item in trait_items {
+                            // Create a new rib for the trait_item-specific type
+                            // parameters.
+                            //
+                            // FIXME #4951: Do we need a node ID here?
+
+                            let type_parameters = match trait_item.node {
+                                ast::MethodTraitItem(ref sig, _) => {
+                                    HasTypeParameters(&sig.generics,
+                                                      FnSpace,
+                                                      MethodRibKind)
+                                }
+                                ast::TypeTraitItem(..) => {
+                                    this.check_if_primitive_type_name(trait_item.ident.name,
+                                                                      trait_item.span);
+                                    NoTypeParameters
+                                }
+                            };
+                            this.with_type_parameter_rib(type_parameters, |this| {
+                                visit::walk_trait_item(this, trait_item)
+                            });
+                        }
+                    });
                 });
-
-                self.type_ribs.pop();
             }
 
             ItemMod(_) | ItemForeignMod(_) => {
@@ -2030,8 +2024,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         visit::walk_generics(self, generics);
     }
 
-    fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T where
-        F: FnOnce(&mut Resolver) -> T,
+    fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
+        where F: FnOnce(&mut Resolver) -> T
     {
         // Handle nested impls (inside fn bodies)
         let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
@@ -2044,29 +2038,44 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                      opt_trait_ref: Option<&TraitRef>,
                                      f: F)
                                      -> T
-        where F: FnOnce(&mut Resolver) -> T,
+        where F: FnOnce(&mut Resolver, Option<DefId>) -> T
     {
         let mut new_val = None;
+        let mut new_id = None;
         if let Some(trait_ref) = opt_trait_ref {
-            match self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, 0) {
-                Ok(path_res) => {
-                    self.record_def(trait_ref.ref_id, path_res);
-                    new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
-                }
-                Err(_) => { /* error was already reported */ }
+            if let Ok(path_res) = self.resolve_trait_reference(trait_ref.ref_id,
+                                                               &trait_ref.path, 0) {
+                assert!(path_res.depth == 0);
+                self.record_def(trait_ref.ref_id, path_res);
+                new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
+                new_id = Some(path_res.base_def.def_id());
             }
             visit::walk_trait_ref(self, trait_ref);
         }
         let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
-        let result = f(self);
+        let result = f(self, new_id);
         self.current_trait_ref = original_trait_ref;
         result
     }
 
+    fn with_self_rib<F>(&mut self, self_def: Def, f: F)
+        where F: FnOnce(&mut Resolver)
+    {
+        let mut self_type_rib = Rib::new(NormalRibKind);
+
+        // plain insert (no renaming, types are not currently hygienic....)
+        let name = special_names::type_self;
+        self_type_rib.bindings.insert(name, DlDef(self_def));
+        self.type_ribs.push(self_type_rib);
+        f(self);
+        self.type_ribs.pop();
+    }
+
     fn resolve_implementation(&mut self,
                               generics: &Generics,
                               opt_trait_reference: &Option<TraitRef>,
                               self_type: &Ty,
+                              item_id: NodeId,
                               impl_items: &[P<ImplItem>]) {
         // If applicable, create a rib for the type parameters.
         self.with_type_parameter_rib(HasTypeParameters(generics,
@@ -2077,40 +2086,42 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             this.visit_generics(generics);
 
             // Resolve the trait reference, if necessary.
-            this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this| {
+            this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
                 // Resolve the self type.
                 this.visit_ty(self_type);
 
-                this.with_current_self_type(self_type, |this| {
-                    for impl_item in impl_items {
-                        match impl_item.node {
-                            MethodImplItem(ref sig, _) => {
-                                // If this is a trait impl, ensure the method
-                                // exists in trait
-                                this.check_trait_item(impl_item.ident.name,
-                                                      impl_item.span);
-
-                                // We also need a new scope for the method-
-                                // specific type parameters.
-                                let type_parameters =
-                                    HasTypeParameters(&sig.generics,
-                                                      FnSpace,
-                                                      MethodRibKind);
-                                this.with_type_parameter_rib(type_parameters, |this| {
-                                    visit::walk_impl_item(this, impl_item);
-                                });
-                            }
-                            TypeImplItem(ref ty) => {
-                                // If this is a trait impl, ensure the method
-                                // exists in trait
-                                this.check_trait_item(impl_item.ident.name,
-                                                      impl_item.span);
+                this.with_self_rib(DefSelfTy(trait_id, Some((item_id, self_type.id))), |this| {
+                    this.with_current_self_type(self_type, |this| {
+                        for impl_item in impl_items {
+                            match impl_item.node {
+                                MethodImplItem(ref sig, _) => {
+                                    // If this is a trait impl, ensure the method
+                                    // exists in trait
+                                    this.check_trait_item(impl_item.ident.name,
+                                                          impl_item.span);
+
+                                    // We also need a new scope for the method-
+                                    // specific type parameters.
+                                    let type_parameters =
+                                        HasTypeParameters(&sig.generics,
+                                                          FnSpace,
+                                                          MethodRibKind);
+                                    this.with_type_parameter_rib(type_parameters, |this| {
+                                        visit::walk_impl_item(this, impl_item);
+                                    });
+                                }
+                                TypeImplItem(ref ty) => {
+                                    // If this is a trait impl, ensure the method
+                                    // exists in trait
+                                    this.check_trait_item(impl_item.ident.name,
+                                                          impl_item.span);
 
-                                this.visit_ty(ty);
+                                    this.visit_ty(ty);
+                                }
+                                ast::MacImplItem(_) => {}
                             }
-                            ast::MacImplItem(_) => {}
                         }
-                    }
+                    });
                 });
             });
         });
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index ba279dea5a2..1a19d4a1e45 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -248,7 +248,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
 
             def::DefFn(..) => Some(recorder::FnRef),
 
-            def::DefSelfTy(_) |
+            def::DefSelfTy(..) |
             def::DefRegion(_) |
             def::DefLabel(_) |
             def::DefTyParam(..) |
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 7a93873af03..355b866013b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -56,7 +56,7 @@ use middle::privacy::{AllPublic, LastMod};
 use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
 use middle::traits;
 use middle::ty::{self, RegionEscape, Ty};
-use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
+use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
              ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::ppaux::{self, Repr, UserString};
@@ -872,24 +872,11 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>(
         }
     }
 
-    if candidates.len() > 1 {
-        span_err!(tcx.sess, binding.span, E0217,
-            "ambiguous associated type: `{}` defined in multiple supertraits `{}`",
-                    token::get_name(binding.item_name),
-                    candidates.user_string(tcx));
-        return Err(ErrorReported);
-    }
-
-    let candidate = match candidates.pop() {
-        Some(c) => c,
-        None => {
-            span_err!(tcx.sess, binding.span, E0218,
-                "no associated type `{}` defined in `{}`",
-                        token::get_name(binding.item_name),
-                        trait_ref.user_string(tcx));
-            return Err(ErrorReported);
-        }
-    };
+    let candidate = try!(one_bound_for_assoc_type(tcx,
+                                                  candidates,
+                                                  &trait_ref.user_string(tcx),
+                                                  &token::get_name(binding.item_name),
+                                                  binding.span));
 
     Ok(ty::Binder(ty::ProjectionPredicate {             // <-------------------------+
         projection_ty: ty::ProjectionTy {               //                           |
@@ -1042,6 +1029,81 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt,
               type_str, trait_str, name);
 }
 
+// Search for a bound on a type parameter which includes the associated item
+// given by assoc_name. ty_param_node_id is the node id for the type parameter
+// (which might be `Self`, but only if it is the `Self` of a trait, not an
+// impl). This function will fail if there are no suitable bounds or there is
+// any ambiguity.
+fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>,
+                                   ty_param_node_id: ast::NodeId,
+                                   assoc_name: ast::Name,
+                                   span: Span)
+                                   -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
+{
+    let tcx = this.tcx();
+
+    let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) {
+        Ok(v) => v,
+        Err(ErrorReported) => {
+            return Err(ErrorReported);
+        }
+    };
+
+    // Ensure the super predicates and stop if we encountered an error.
+    if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) {
+        return Err(ErrorReported);
+    }
+
+    // Check that there is exactly one way to find an associated type with the
+    // correct name.
+    let suitable_bounds: Vec<_> =
+        traits::transitive_bounds(tcx, &bounds)
+        .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name))
+        .collect();
+
+    let ty_param_name = tcx.type_parameter_def(ty_param_node_id).name;
+    one_bound_for_assoc_type(tcx,
+                             suitable_bounds,
+                             &token::get_name(ty_param_name),
+                             &token::get_name(assoc_name),
+                             span)
+}
+
+
+// Checks that bounds contains exactly one element and reports appropriate
+// errors otherwise.
+fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                  bounds: Vec<ty::PolyTraitRef<'tcx>>,
+                                  ty_param_name: &str,
+                                  assoc_name: &str,
+                                  span: Span)
+    -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
+{
+    if bounds.len() == 0 {
+        span_err!(tcx.sess, span, E0220,
+                  "associated type `{}` not found for `{}`",
+                  assoc_name,
+                  ty_param_name);
+        return Err(ErrorReported);
+    }
+
+    if bounds.len() > 1 {
+        span_err!(tcx.sess, span, E0221,
+                  "ambiguous associated type `{}` in bounds of `{}`",
+                  assoc_name,
+                  ty_param_name);
+
+        for bound in &bounds {
+            span_note!(tcx.sess, span,
+                       "associated type `{}` could derive from `{}`",
+                       ty_param_name,
+                       bound.user_string(tcx));
+        }
+    }
+
+    Ok(bounds[0].clone())
+}
+
 // Create a type from a a path to an associated type.
 // For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C
 // and item_segment is the path segment for D. We return a type and a def for
@@ -1062,10 +1124,55 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
 
     check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
 
-    // Check that the path prefix given by ty/ty_path_def is a type parameter/Self.
-    match (&ty.sty, ty_path_def) {
+    // Find the type of the associated item, and the trait where the associated
+    // item is declared.
+    let bound = match (&ty.sty, ty_path_def) {
+        (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => {
+            // `Self` in an impl of a trait - we have a concrete self type and a
+            // trait reference.
+            match tcx.map.expect_item(impl_id).node {
+                ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => {
+                    if this.ensure_super_predicates(span, trait_did).is_err() {
+                        return (tcx.types.err, ty_path_def);
+                    }
+
+                    let trait_segment = &trait_ref.path.segments.last().unwrap();
+                    let trait_ref = ast_path_to_mono_trait_ref(this,
+                                                               &ExplicitRscope,
+                                                               span,
+                                                               PathParamMode::Explicit,
+                                                               trait_did,
+                                                               Some(ty),
+                                                               trait_segment);
+
+                    let candidates: Vec<ty::PolyTraitRef> =
+                        traits::supertraits(tcx, ty::Binder(trait_ref.clone()))
+                        .filter(|r| this.trait_defines_associated_type_named(r.def_id(),
+                                                                             assoc_name))
+                        .collect();
+
+                    match one_bound_for_assoc_type(tcx,
+                                                   candidates,
+                                                   "Self",
+                                                   &token::get_name(assoc_name),
+                                                   span) {
+                        Ok(bound) => bound,
+                        Err(ErrorReported) => return (tcx.types.err, ty_path_def),
+                    }
+                }
+                _ => unreachable!()
+            }
+        }
         (&ty::ty_param(_), def::DefTyParam(..)) |
-        (&ty::ty_param(_), def::DefSelfTy(_)) => {}
+        (&ty::ty_param(_), def::DefSelfTy(Some(_), None)) => {
+            // A type parameter or Self, we need to find the associated item from
+            // a bound.
+            let ty_param_node_id = ty_path_def.local_node_id();
+            match find_bound_for_assoc_item(this, ty_param_node_id, assoc_name, span) {
+                Ok(bound) => bound,
+                Err(ErrorReported) => return (tcx.types.err, ty_path_def),
+            }
+        }
         _ => {
             report_ambiguous_associated_type(tcx,
                                              span,
@@ -1074,61 +1181,15 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
                                              &token::get_name(assoc_name));
             return (tcx.types.err, ty_path_def);
         }
-    }
-
-    let ty_param_node_id = ty_path_def.local_node_id();
-    let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name;
-
-    let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) {
-        Ok(v) => v,
-        Err(ErrorReported) => {
-            return (tcx.types.err, ty_path_def);
-        }
     };
 
-    // Ensure the super predicates and stop if we encountered an error.
-    if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) {
-        return (this.tcx().types.err, ty_path_def);
-    }
-
-    // Check that there is exactly one way to find an associated type with the
-    // correct name.
-    let mut suitable_bounds: Vec<_> =
-        traits::transitive_bounds(tcx, &bounds)
-        .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name))
-        .collect();
-
-    if suitable_bounds.len() == 0 {
-        span_err!(tcx.sess, span, E0220,
-                          "associated type `{}` not found for type parameter `{}`",
-                                  token::get_name(assoc_name),
-                                  token::get_name(ty_param_name));
-        return (this.tcx().types.err, ty_path_def);
-    }
-
-    if suitable_bounds.len() > 1 {
-        span_err!(tcx.sess, span, E0221,
-                          "ambiguous associated type `{}` in bounds of `{}`",
-                                  token::get_name(assoc_name),
-                                  token::get_name(ty_param_name));
-
-        for suitable_bound in &suitable_bounds {
-            span_note!(this.tcx().sess, span,
-                       "associated type `{}` could derive from `{}`",
-                       token::get_name(ty_param_name),
-                       suitable_bound.user_string(this.tcx()));
-        }
-    }
-
-    let suitable_bound = suitable_bounds.pop().unwrap().clone();
-    let trait_did = suitable_bound.0.def_id;
-
-    let ty = this.projected_ty_from_poly_trait_ref(span, suitable_bound, assoc_name);
+    let trait_did = bound.0.def_id;
+    let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
 
     let item_did = if trait_did.krate == ast::LOCAL_CRATE {
         // `ty::trait_items` used below requires information generated
         // by type collection, which may be in progress at this point.
-        match this.tcx().map.expect_item(trait_did.node).node {
+        match tcx.map.expect_item(trait_did.node).node {
             ast::ItemTrait(_, _, _, ref trait_items) => {
                 let item = trait_items.iter()
                                       .find(|i| i.ident.name == assoc_name)
@@ -1138,7 +1199,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
             _ => unreachable!()
         }
     } else {
-        let trait_items = ty::trait_items(this.tcx(), trait_did);
+        let trait_items = ty::trait_items(tcx, trait_did);
         let item = trait_items.iter().find(|i| i.name() == assoc_name);
         item.expect("missing associated type").def_id()
     };
@@ -1174,14 +1235,13 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
 
     debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
 
-    let trait_ref =
-        ast_path_to_mono_trait_ref(this,
-                                   rscope,
-                                   span,
-                                   param_mode,
-                                   trait_def_id,
-                                   Some(self_ty),
-                                   trait_segment);
+    let trait_ref = ast_path_to_mono_trait_ref(this,
+                                               rscope,
+                                               span,
+                                               param_mode,
+                                               trait_def_id,
+                                               Some(self_ty),
+                                               trait_segment);
 
     debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
 
@@ -1221,20 +1281,20 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>,
     }
 }
 
-// Note that both base_segments and assoc_segments may be empty, although not at
-// the same time.
-pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
-                                        rscope: &RegionScope,
-                                        span: Span,
-                                        param_mode: PathParamMode,
-                                        def: &def::Def,
-                                        opt_self_ty: Option<Ty<'tcx>>,
-                                        base_segments: &[ast::PathSegment],
-                                        assoc_segments: &[ast::PathSegment])
-                                        -> Ty<'tcx> {
+// Check the base def in a PathResolution and convert it to a Ty. If there are
+// associated types in the PathResolution, these will need to be seperately
+// resolved.
+fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
+                        rscope: &RegionScope,
+                        span: Span,
+                        param_mode: PathParamMode,
+                        def: &def::Def,
+                        opt_self_ty: Option<Ty<'tcx>>,
+                        base_segments: &[ast::PathSegment])
+                        -> Ty<'tcx> {
     let tcx = this.tcx();
 
-    let base_ty = match *def {
+    match *def {
         def::DefTrait(trait_def_id) => {
             // N.B. this case overlaps somewhat with
             // TyObjectSum, see that fn for details
@@ -1258,18 +1318,28 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
         }
         def::DefTy(did, _) | def::DefStruct(did) => {
             check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS);
-            ast_path_to_ty(this, rscope, span,
-                           param_mode, did,
+            ast_path_to_ty(this,
+                           rscope,
+                           span,
+                           param_mode,
+                           did,
                            base_segments.last().unwrap())
         }
         def::DefTyParam(space, index, _, name) => {
             check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
             ty::mk_param(tcx, space, index, name)
         }
-        def::DefSelfTy(_) => {
-            // N.b.: resolve guarantees that the this type only appears in a
-            // trait, which we rely upon in various places when creating
-            // substs.
+        def::DefSelfTy(_, Some((_, self_ty_id))) => {
+            // Self in impl (we know the concrete type).
+            check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
+            if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&self_ty_id) {
+                ty
+            } else {
+                tcx.sess.span_bug(span, "self type has not been fully resolved")
+            }
+        }
+        def::DefSelfTy(Some(_), None) => {
+            // Self in trait.
             check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
             ty::mk_self_type(tcx)
         }
@@ -1289,6 +1359,9 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
             // FIXME(#22519) This part of the resolution logic should be
             // avoided entirely for that form, once we stop needed a Def
             // for `associated_path_def_to_ty`.
+            // Fixing this will also let use resolve <Self>::Foo the same way we
+            // resolve Self::Foo, at the moment we can't resolve the former because
+            // we don't have the trait information around, which is just sad.
 
             if !base_segments.is_empty() {
                 span_err!(tcx.sess,
@@ -1309,11 +1382,29 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
                       "found value name used as a type: {:?}", *def);
             return this.tcx().types.err;
         }
-    };
+    }
+}
 
-    // If any associated type segments remain, attempt to resolve them.
-    let mut ty = base_ty;
+// Note that both base_segments and assoc_segments may be empty, although not at
+// the same time.
+pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
+                                        rscope: &RegionScope,
+                                        span: Span,
+                                        param_mode: PathParamMode,
+                                        def: &def::Def,
+                                        opt_self_ty: Option<Ty<'tcx>>,
+                                        base_segments: &[ast::PathSegment],
+                                        assoc_segments: &[ast::PathSegment])
+                                        -> Ty<'tcx> {
+    let mut ty = base_def_to_ty(this,
+                                rscope,
+                                span,
+                                param_mode,
+                                def,
+                                opt_self_ty,
+                                base_segments);
     let mut def = *def;
+    // If any associated type segments remain, attempt to resolve them.
     for segment in assoc_segments {
         if ty.sty == ty::ty_err {
             break;
@@ -1997,7 +2088,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
                                 check_type_argument_count(tcx, b.trait_ref.path.span,
                                                           parameters.types().len(), 0, 0);
                             }
-                            if parameters.lifetimes().len() > 0{
+                            if parameters.lifetimes().len() > 0 {
                                 report_lifetime_number_error(tcx, b.trait_ref.path.span,
                                                              parameters.lifetimes().len(), 0);
                             }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 156fbfede9c..ce1227608cf 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3341,11 +3341,17 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
 
           let def = path_res.base_def;
           if path_res.depth == 0 {
-              let (scheme, predicates) =
-                  type_scheme_and_predicates_for_def(fcx, expr.span, def);
-              instantiate_path(fcx, &path.segments,
-                               scheme, &predicates,
-                               opt_self_ty, def, expr.span, id);
+              let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
+                                                                            expr.span,
+                                                                            def);
+              instantiate_path(fcx,
+                               &path.segments,
+                               scheme,
+                               &predicates,
+                               opt_self_ty,
+                               def,
+                               expr.span,
+                               id);
           } else {
               let ty_segments = path.segments.init();
               let base_ty_end = path.segments.len() - path_res.depth;
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 8f1b8bf1092..95b943b2547 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -547,14 +547,15 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>,
     if let ast::TyPath(None, _) = ast_ty.node {
         let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap();
         match path_res.base_def {
-            def::DefSelfTy(node_id) =>
-                path_res.depth == 0 && node_id == param_id,
-
-            def::DefTyParam(_, _, def_id, _) =>
-                path_res.depth == 0 && def_id == local_def(param_id),
-
-            _ =>
-                false,
+            def::DefSelfTy(Some(def_id), None) => {
+                path_res.depth == 0 && def_id.node == param_id
+            }
+            def::DefTyParam(_, _, def_id, _) => {
+                path_res.depth == 0 && def_id == local_def(param_id)
+            }
+            _ => {
+                false
+            }
         }
     } else {
         false
@@ -1814,7 +1815,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                     ty::ty_param(p) => if p.idx > cur_idx {
                         span_err!(tcx.sess, path.span, E0128,
                                   "type parameters with a default cannot use \
-                                  forward declared identifiers");
+                                   forward declared identifiers");
                         },
                         _ => {}
                     }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index f13047d3725..dd0c7d716b7 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -14,7 +14,6 @@ use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
 use ast::{StmtExpr, StmtSemi};
 use ast::TokenTree;
 use ast;
-use ast_util::path_to_ident;
 use ext::mtwt;
 use ext::build::AstBuilder;
 use attr;
@@ -34,30 +33,6 @@ use visit;
 use visit::Visitor;
 use std_inject;
 
-pub fn expand_type(t: P<ast::Ty>,
-                   fld: &mut MacroExpander,
-                   impl_ty: Option<P<ast::Ty>>)
-                   -> P<ast::Ty> {
-    debug!("expanding type {:?} with impl_ty {:?}", t, impl_ty);
-    let t = match (t.node.clone(), impl_ty) {
-        // Expand uses of `Self` in impls to the concrete type.
-        (ast::Ty_::TyPath(None, ref path), Some(ref impl_ty)) => {
-            let path_as_ident = path_to_ident(path);
-            // Note unhygenic comparison here. I think this is correct, since
-            // even though `Self` is almost just a type parameter, the treatment
-            // for this expansion is as if it were a keyword.
-            if path_as_ident.is_some() &&
-               path_as_ident.unwrap().name == token::special_idents::type_self.name {
-                impl_ty.clone()
-            } else {
-                t
-            }
-        }
-        _ => t
-    };
-    fold::noop_fold_ty(t, fld)
-}
-
 pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
     e.and_then(|ast::Expr {id, node, span}| match node {
         // expr_mac should really be expr_ext or something; it's the
@@ -1354,13 +1329,11 @@ fn expand_and_rename_method(sig: ast::MethodSig, body: P<ast::Block>,
 /// A tree-folder that performs macro expansion
 pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
-    // The type of the impl currently being expanded.
-    current_impl_type: Option<P<ast::Ty>>,
 }
 
 impl<'a, 'b> MacroExpander<'a, 'b> {
     pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
-        MacroExpander { cx: cx, current_impl_type: None }
+        MacroExpander { cx: cx }
     }
 }
 
@@ -1374,14 +1347,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 
     fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
-        let prev_type = self.current_impl_type.clone();
-        if let ast::Item_::ItemImpl(_, _, _, _, ref ty, _) = item.node {
-            self.current_impl_type = Some(ty.clone());
-        }
-
-        let result = expand_item(item, self);
-        self.current_impl_type = prev_type;
-        result
+        expand_item(item, self)
     }
 
     fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
@@ -1410,11 +1376,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
             .into_iter().map(|i| i.expect_impl_item()).collect()
     }
 
-    fn fold_ty(&mut self, t: P<ast::Ty>) -> P<ast::Ty> {
-        let impl_type = self.current_impl_type.clone();
-        expand_type(t, self, impl_type)
-    }
-
     fn new_span(&mut self, span: Span) -> Span {
         new_span(self.cx, span)
     }
diff --git a/src/test/compile-fail/self-impl.rs b/src/test/compile-fail/self-impl.rs
new file mode 100644
index 00000000000..d058c6a5a3b
--- /dev/null
+++ b/src/test/compile-fail/self-impl.rs
@@ -0,0 +1,40 @@
+// Copyright 2015 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 unsupported uses of `Self` in impls don't crash
+
+struct Bar;
+
+trait Foo {
+    type Baz;
+}
+
+trait SuperFoo {
+    type SuperBaz;
+}
+
+impl Foo for Bar {
+    type Baz = bool;
+}
+
+impl SuperFoo for Bar {
+    type SuperBaz = bool;
+}
+
+impl Bar {
+    fn f() {
+        let _: <Self>::Baz = true;
+//~^ERROR: ambiguous associated type; specify the type using the syntax `<Bar as Trait>::Baz`
+        let _: Self::Baz = true;
+//~^ERROR: ambiguous associated type; specify the type using the syntax `<Bar as Trait>::Baz`
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs
index c9837da58e7..bb7e02d0d8b 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs
@@ -12,7 +12,7 @@
 
 trait One<A> { fn foo(&self) -> A; }
 
-fn foo(_: &One()) //~ ERROR no associated type `Output` defined in `One<()>`
+fn foo(_: &One()) //~ ERROR associated type `Output` not found for `One<()>`
 {}
 
 fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
index 9f0682df3fe..20fdd52b82a 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs
@@ -14,7 +14,7 @@ trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); }
 
 fn foo(_: &Three())
 //~^ ERROR wrong number of type arguments
-//~| ERROR no associated type `Output`
+//~| ERROR associated type `Output` not found
 {}
 
 fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
index 40635cf3ddd..027fa6b0fe3 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs
@@ -14,7 +14,7 @@ trait Zero { fn dummy(&self); }
 
 fn foo(_: Zero())
     //~^ ERROR wrong number of type arguments
-    //~| ERROR no associated type `Output` defined in `Zero`
+    //~| ERROR associated type `Output` not found for `Zero`
 {}
 
 fn main() { }
diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
index e6e18d996b9..04bbfc445ed 100644
--- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
+++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs
@@ -14,6 +14,6 @@ trait Trait {}
 
 fn f<F:Trait(isize) -> isize>(x: F) {}
 //~^ ERROR wrong number of type arguments: expected 0, found 1
-//~| ERROR no associated type `Output`
+//~| ERROR associated type `Output` not found
 
 fn main() {}
diff --git a/src/test/run-pass/self-impl.rs b/src/test/run-pass/self-impl.rs
index c32773aa88c..688b66a0a87 100644
--- a/src/test/run-pass/self-impl.rs
+++ b/src/test/run-pass/self-impl.rs
@@ -22,6 +22,17 @@ impl Foo {
     fn foo(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
         Foo
     }
+
+    fn baz() {
+        // Test that Self cannot be shadowed.
+        type Foo = i32;
+        // There is no empty method on i32.
+        Self::empty();
+
+        let _: Self = Foo;
+    }
+
+    fn empty() {}
 }
 
 // Test uses when implementing a trait and with a type parameter.
@@ -29,13 +40,31 @@ pub struct Baz<X> {
     pub f: X,
 }
 
-trait Bar<X> {
-    fn bar(x: Self, y: &Self, z: Box<Self>) -> Self;
+trait SuperBar {
+    type SuperQux;
+}
+
+trait Bar<X>: SuperBar {
+    type Qux;
+
+    fn bar(x: Self, y: &Self, z: Box<Self>, _: Self::SuperQux) -> Self;
     fn dummy(&self, x: X) { }
 }
 
+impl SuperBar for Box<Baz<isize>> {
+    type SuperQux = bool;
+}
+
 impl Bar<isize> for Box<Baz<isize>> {
-    fn bar(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
+    type Qux = i32;
+
+    fn bar(_x: Self, _y: &Self, _z: Box<Self>, _: Self::SuperQux) -> Self {
+        let _: Self::Qux = 42;
+        let _: <Self as Bar<isize>>::Qux = 42;
+
+        let _: Self::SuperQux = true;
+        let _: <Self as SuperBar>::SuperQux = true;
+
         box Baz { f: 42 }
     }
 }
@@ -43,6 +72,7 @@ impl Bar<isize> for Box<Baz<isize>> {
 fn main() {
     let _: Foo = Foo::foo(Foo, &Foo, box Foo);
     let _: Box<Baz<isize>> = Bar::bar(box Baz { f: 42 },
-                                    &box Baz { f: 42 },
-                                    box box Baz { f: 42 });
+                                      &box Baz { f: 42 },
+                                      box box Baz { f: 42 },
+                                      true);
 }