about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <arielb1@mail.tau.ac.il>2015-05-26 17:12:39 +0300
committerAriel Ben-Yehuda <arielb1@mail.tau.ac.il>2015-05-26 17:22:29 +0300
commitae10e478eb61e75ebf3a7bf672b34b582555fd8e (patch)
treeb4fb3e99356b26a885cc53d73f6924d7bc45c25e
parentc654a07d29c77b5a023cb9d36dfc61811349f64e (diff)
downloadrust-ae10e478eb61e75ebf3a7bf672b34b582555fd8e.tar.gz
rust-ae10e478eb61e75ebf3a7bf672b34b582555fd8e.zip
Implement defaults for associated types
-rw-r--r--src/librustc/metadata/decoder.rs35
-rw-r--r--src/librustc/metadata/encoder.rs23
-rw-r--r--src/librustc/middle/traits/project.rs50
-rw-r--r--src/librustc/middle/ty.rs5
-rw-r--r--src/librustc/util/ppaux.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs17
-rw-r--r--src/librustc_typeck/collect.rs48
-rw-r--r--src/librustdoc/clean/inline.rs8
-rw-r--r--src/librustdoc/clean/mod.rs69
-rw-r--r--src/test/run-pass/default-associated-types.rs30
10 files changed, 167 insertions, 120 deletions
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 42dcc9661ca..5eefb99b058 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -252,6 +252,13 @@ fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx>
                   |_, did| translate_def_id(cdata, did))
 }
 
+fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option<Ty<'tcx>> {
+    reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| {
+        parse_ty_data(tp.data, cdata.cnum, tp.start, tcx,
+                      |_, did| translate_def_id(cdata, did))
+    })
+}
+
 fn doc_method_fty<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>,
                         cdata: Cmd) -> ty::BareFnTy<'tcx> {
     let tp = reader::get_doc(doc, tag_item_method_fty);
@@ -875,24 +882,24 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
                                     id: ast::NodeId,
                                     tcx: &ty::ctxt<'tcx>)
                                     -> ty::ImplOrTraitItem<'tcx> {
-    let method_doc = lookup_item(id, cdata.data());
+    let item_doc = lookup_item(id, cdata.data());
 
-    let def_id = item_def_id(method_doc, cdata);
+    let def_id = item_def_id(item_doc, cdata);
 
-    let container_id = item_require_parent_item(cdata, method_doc);
+    let container_id = item_require_parent_item(cdata, item_doc);
     let container_doc = lookup_item(container_id.node, cdata.data());
     let container = match item_family(container_doc) {
         Trait => TraitContainer(container_id),
         _ => ImplContainer(container_id),
     };
 
-    let name = item_name(&*intr, method_doc);
-    let vis = item_visibility(method_doc);
+    let name = item_name(&*intr, item_doc);
+    let vis = item_visibility(item_doc);
 
-    match item_sort(method_doc) {
+    match item_sort(item_doc) {
         Some('C') => {
-            let ty = doc_type(method_doc, tcx, cdata);
-            let default = get_provided_source(method_doc, cdata);
+            let ty = doc_type(item_doc, tcx, cdata);
+            let default = get_provided_source(item_doc, cdata);
             ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
                 name: name,
                 ty: ty,
@@ -903,11 +910,11 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
             }))
         }
         Some('r') | Some('p') => {
-            let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
-            let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
-            let fty = doc_method_fty(method_doc, tcx, cdata);
-            let explicit_self = get_explicit_self(method_doc);
-            let provided_source = get_provided_source(method_doc, cdata);
+            let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics);
+            let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
+            let fty = doc_method_fty(item_doc, tcx, cdata);
+            let explicit_self = get_explicit_self(item_doc);
+            let provided_source = get_provided_source(item_doc, cdata);
 
             ty::MethodTraitItem(Rc::new(ty::Method::new(name,
                                                         generics,
@@ -920,8 +927,10 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
                                                         provided_source)))
         }
         Some('t') => {
+            let ty = maybe_doc_type(item_doc, tcx, cdata);
             ty::TypeTraitItem(Rc::new(ty::AssociatedType {
                 name: name,
+                ty: ty,
                 vis: vis,
                 def_id: def_id,
                 container: container,
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 0908ffd249f..8eefb4d5011 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -894,12 +894,12 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     rbml_w.end_tag();
 }
 
-fn encode_info_for_associated_type(ecx: &EncodeContext,
-                                   rbml_w: &mut Encoder,
-                                   associated_type: &ty::AssociatedType,
-                                   impl_path: PathElems,
-                                   parent_id: NodeId,
-                                   impl_item_opt: Option<&ast::ImplItem>) {
+fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
+                                             rbml_w: &mut Encoder,
+                                             associated_type: &ty::AssociatedType<'tcx>,
+                                             impl_path: PathElems,
+                                             parent_id: NodeId,
+                                             impl_item_opt: Option<&ast::ImplItem>) {
     debug!("encode_info_for_associated_type({:?},{:?})",
            associated_type.def_id,
            token::get_name(associated_type.name));
@@ -913,8 +913,6 @@ fn encode_info_for_associated_type(ecx: &EncodeContext,
     encode_parent_item(rbml_w, local_def(parent_id));
     encode_item_sort(rbml_w, 't');
 
-    encode_bounds_and_type_for_item(rbml_w, ecx, associated_type.def_id.local_id());
-
     let stab = stability::lookup(ecx.tcx, associated_type.def_id);
     encode_stability(rbml_w, stab);
 
@@ -923,7 +921,14 @@ fn encode_info_for_associated_type(ecx: &EncodeContext,
 
     if let Some(ii) = impl_item_opt {
         encode_attributes(rbml_w, &ii.attrs);
-        encode_type(ecx, rbml_w, ty::node_id_to_type(ecx.tcx, ii.id));
+    } else {
+        encode_predicates(rbml_w, ecx,
+                          &ty::lookup_predicates(ecx.tcx, associated_type.def_id),
+                          tag_item_generics);
+    }
+
+    if let Some(ty) = associated_type.ty {
+        encode_type(ecx, rbml_w, ty);
     }
 
     rbml_w.end_tag();
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index f6bde80e298..700aaad8b72 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -857,37 +857,39 @@ fn confirm_impl_candidate<'cx,'tcx>(
     -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
 {
     // there don't seem to be nicer accessors to these:
-    let impl_items_map = selcx.tcx().impl_items.borrow();
     let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
 
-    let impl_items = impl_items_map.get(&impl_vtable.impl_def_id).unwrap();
-    let mut impl_ty = None;
-    for impl_item in impl_items {
-        let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() {
-            ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
-            ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; }
-        };
-
-        if assoc_type.name != obligation.predicate.item_name {
-            continue;
+    for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] {
+        if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] {
+            if assoc_ty.name == obligation.predicate.item_name {
+                return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs),
+                        impl_vtable.nested.into_vec());
+            }
         }
-
-        let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
-        impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
-        break;
     }
 
-    match impl_ty {
-        Some(ty) => (ty, impl_vtable.nested.into_vec()),
-        None => {
-            // This means that the impl is missing a
-            // definition for the associated type. This error
-            // ought to be reported by the type checker method
-            // `check_impl_items_against_trait`, so here we
-            // just return ty_err.
-            (selcx.tcx().types.err, vec!())
+    let trait_ref = obligation.predicate.trait_ref;
+    for trait_item in ty::trait_items(selcx.tcx(), trait_ref.def_id).iter() {
+        if let &ty::TypeTraitItem(ref assoc_ty) = trait_item {
+            if assoc_ty.name == obligation.predicate.item_name {
+                if let Some(ty) = assoc_ty.ty {
+                    return (ty.subst(selcx.tcx(), trait_ref.substs),
+                            impl_vtable.nested.into_vec());
+                } else {
+                    // This means that the impl is missing a
+                    // definition for the associated type. This error
+                    // ought to be reported by the type checker method
+                    // `check_impl_items_against_trait`, so here we
+                    // just return ty_err.
+                    return (selcx.tcx().types.err, vec!());
+                }
+            }
         }
     }
+
+    selcx.tcx().sess.span_bug(obligation.cause.span,
+                              &format!("No associated type for {}",
+                                       trait_ref.repr(selcx.tcx())));
 }
 
 impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 2ccbb0c5c10..a67a968ea2c 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -136,7 +136,7 @@ impl ImplOrTraitItemContainer {
 pub enum ImplOrTraitItem<'tcx> {
     ConstTraitItem(Rc<AssociatedConst<'tcx>>),
     MethodTraitItem(Rc<Method<'tcx>>),
-    TypeTraitItem(Rc<AssociatedType>),
+    TypeTraitItem(Rc<AssociatedType<'tcx>>),
 }
 
 impl<'tcx> ImplOrTraitItem<'tcx> {
@@ -267,8 +267,9 @@ pub struct AssociatedConst<'tcx> {
 }
 
 #[derive(Clone, Copy, Debug)]
-pub struct AssociatedType {
+pub struct AssociatedType<'tcx> {
     pub name: ast::Name,
+    pub ty: Option<Ty<'tcx>>,
     pub vis: ast::Visibility,
     pub def_id: ast::DefId,
     pub container: ImplOrTraitItemContainer,
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index cf2911ab182..6f71def1188 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -1077,7 +1077,7 @@ impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> {
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::AssociatedType {
+impl<'tcx> Repr<'tcx> for ty::AssociatedType<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
         format!("AssociatedType(name: {}, vis: {}, def_id: {})",
                 self.name.repr(tcx),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index eb6e90414e3..05aad1d64f7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1070,7 +1070,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // Check for missing items from trait
     let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id);
     let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id);
-    let mut missing_methods = Vec::new();
+    let mut missing_items = Vec::new();
     for trait_item in &*trait_items {
         match *trait_item {
             ty::ConstTraitItem(ref associated_const) => {
@@ -1086,8 +1086,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     associated_consts.iter().any(|ac| ac.default.is_some() &&
                                                  ac.name == associated_const.name);
                 if !is_implemented && !is_provided {
-                    missing_methods.push(format!("`{}`",
-                                                 token::get_name(associated_const.name)));
+                    missing_items.push(format!("`{}`",
+                                               token::get_name(associated_const.name)));
                 }
             }
             ty::MethodTraitItem(ref trait_method) => {
@@ -1103,7 +1103,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 let is_provided =
                     provided_methods.iter().any(|m| m.name == trait_method.name);
                 if !is_implemented && !is_provided {
-                    missing_methods.push(format!("`{}`", token::get_name(trait_method.name)));
+                    missing_items.push(format!("`{}`", token::get_name(trait_method.name)));
                 }
             }
             ty::TypeTraitItem(ref associated_type) => {
@@ -1115,17 +1115,18 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         _ => false,
                     }
                 });
-                if !is_implemented {
-                    missing_methods.push(format!("`{}`", token::get_name(associated_type.name)));
+                let is_provided = associated_type.ty.is_some();
+                if !is_implemented && !is_provided {
+                    missing_items.push(format!("`{}`", token::get_name(associated_type.name)));
                 }
             }
         }
     }
 
-    if !missing_methods.is_empty() {
+    if !missing_items.is_empty() {
         span_err!(tcx.sess, impl_span, E0046,
             "not all trait items implemented, missing: {}",
-            missing_methods.connect(", "));
+            missing_items.connect(", "));
     }
 }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 2fba967b3b2..6507f6dc372 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -718,15 +718,17 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
        .insert(local_def(id), ty::ConstTraitItem(associated_const));
 }
 
-fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                 container: ImplOrTraitItemContainer,
-                                 ident: ast::Ident,
-                                 id: ast::NodeId,
-                                 vis: ast::Visibility)
+fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                     container: ImplOrTraitItemContainer,
+                                     ident: ast::Ident,
+                                     id: ast::NodeId,
+                                     vis: ast::Visibility,
+                                     ty: Option<Ty<'tcx>>)
 {
     let associated_type = Rc::new(ty::AssociatedType {
         name: ident.name,
         vis: vis,
+        ty: ty,
         def_id: local_def(id),
         container: container
     });
@@ -876,21 +878,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
                 if let ast::TypeImplItem(ref ty) = impl_item.node {
                     if opt_trait_ref.is_none() {
                         span_err!(tcx.sess, impl_item.span, E0202,
-                                  "associated items are not allowed in inherent impls");
+                                  "associated types are not allowed in inherent impls");
                     }
 
-                    as_refsociated_type(ccx, ImplContainer(local_def(it.id)),
-                                        impl_item.ident, impl_item.id, impl_item.vis);
-
                     let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
-                    tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
-                                                   TypeScheme {
-                                                       generics: ty::Generics::empty(),
-                                                       ty: typ,
-                                                   });
-                    tcx.predicates.borrow_mut().insert(local_def(impl_item.id),
-                                                       ty::GenericPredicates::empty());
-                    write_ty_to_tcx(tcx, impl_item.id, typ);
+
+                    convert_associated_type(ccx, ImplContainer(local_def(it.id)),
+                                            impl_item.ident, impl_item.id, impl_item.vis,
+                                            Some(typ));
                 }
             }
 
@@ -973,9 +968,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
             // Convert all the associated types.
             for trait_item in trait_items {
                 match trait_item.node {
-                    ast::TypeTraitItem(..) => {
-                        as_refsociated_type(ccx, TraitContainer(local_def(it.id)),
-                                                trait_item.ident, trait_item.id, ast::Public);
+                    ast::TypeTraitItem(_, ref opt_ty) => {
+                        let typ = opt_ty.as_ref().map({
+                            |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
+                        });
+
+                        convert_associated_type(ccx, TraitContainer(local_def(it.id)),
+                                                trait_item.ident, trait_item.id, ast::Public,
+                                                typ);
                     }
                     _ => {}
                 }
@@ -2292,10 +2292,10 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     let lifetimes_in_associated_types: HashSet<_> =
         impl_items.iter()
-                  .filter_map(|item| match item.node {
-                      ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)),
-                      ast::ConstImplItem(..) | ast::MethodImplItem(..) |
-                      ast::MacImplItem(..) => None,
+                  .map(|item| ty::impl_or_trait_item(tcx, local_def(item.id)))
+                  .filter_map(|item| match item {
+                      ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
+                      ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
                   })
                   .flat_map(|ty| ctp::parameters_for_type(ty).into_iter())
                   .filter_map(|p| match p {
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 9c64b7b4ab6..fcc4e5bb96c 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -362,11 +362,13 @@ pub fn build_impl(cx: &DocContext,
             }
             ty::TypeTraitItem(ref assoc_ty) => {
                 let did = assoc_ty.def_id;
-                let type_scheme = ty::lookup_item_type(tcx, did);
-                let predicates = ty::lookup_predicates(tcx, did);
+                let type_scheme = ty::TypeScheme {
+                    ty: assoc_ty.ty.unwrap(),
+                    generics: ty::Generics::empty()
+                };
                 // Not sure the choice of ParamSpace actually matters here,
                 // because an associated type won't have generics on the LHS
-                let typedef = (type_scheme, predicates,
+                let typedef = (type_scheme, ty::GenericPredicates::empty(),
                                subst::ParamSpace::TypeSpace).clean(cx);
                 Some(clean::Item {
                     name: Some(assoc_ty.name.clean(cx)),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 95444bb9158..b5aa27d0b03 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2724,43 +2724,40 @@ impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
     }
 }
 
-impl Clean<Item> for ty::AssociatedType {
+impl<'tcx> Clean<Item> for ty::AssociatedType<'tcx> {
     fn clean(&self, cx: &DocContext) -> Item {
-        // When loading a cross-crate associated type, the bounds for this type
-        // are actually located on the trait/impl itself, so we need to load
-        // all of the generics from there and then look for bounds that are
-        // applied to this associated type in question.
-        let predicates = ty::lookup_predicates(cx.tcx(), self.container.id());
-        let generics = match self.container {
-            ty::TraitContainer(did) => {
-                let def = ty::lookup_trait_def(cx.tcx(), did);
-                (&def.generics, &predicates, subst::TypeSpace).clean(cx)
-            }
-            ty::ImplContainer(did) => {
-                let ty = ty::lookup_item_type(cx.tcx(), did);
-                (&ty.generics, &predicates, subst::TypeSpace).clean(cx)
-            }
-        };
         let my_name = self.name.clean(cx);
-        let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
-            let (name, self_type, trait_, bounds) = match *pred {
-                WherePredicate::BoundPredicate {
-                    ty: QPath { ref name, ref self_type, ref trait_ },
-                    ref bounds
-                } => (name, self_type, trait_, bounds),
-                _ => return None,
-            };
-            if *name != my_name { return None }
-            match **trait_ {
-                ResolvedPath { did, .. } if did == self.container.id() => {}
-                _ => return None,
-            }
-            match **self_type {
-                Generic(ref s) if *s == "Self" => {}
-                _ => return None,
-            }
-            Some(bounds)
-        }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
+
+        let mut bounds = if let ty::TraitContainer(did) = self.container {
+            // When loading a cross-crate associated type, the bounds for this type
+            // are actually located on the trait/impl itself, so we need to load
+            // all of the generics from there and then look for bounds that are
+            // applied to this associated type in question.
+            let def = ty::lookup_trait_def(cx.tcx(), did);
+            let predicates = ty::lookup_predicates(cx.tcx(), did);
+            let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
+            generics.where_predicates.iter().filter_map(|pred| {
+                let (name, self_type, trait_, bounds) = match *pred {
+                    WherePredicate::BoundPredicate {
+                        ty: QPath { ref name, ref self_type, ref trait_ },
+                        ref bounds
+                    } => (name, self_type, trait_, bounds),
+                    _ => return None,
+                };
+                if *name != my_name { return None }
+                match **trait_ {
+                    ResolvedPath { did, .. } if did == self.container.id() => {}
+                    _ => return None,
+                }
+                match **self_type {
+                    Generic(ref s) if *s == "Self" => {}
+                    _ => return None,
+                }
+                Some(bounds)
+            }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
+        } else {
+            vec![]
+        };
 
         // Our Sized/?Sized bound didn't get handled when creating the generics
         // because we didn't actually get our whole set of bounds until just now
@@ -2776,7 +2773,7 @@ impl Clean<Item> for ty::AssociatedType {
             source: DUMMY_SP.clean(cx),
             name: Some(self.name.clean(cx)),
             attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
-            inner: AssociatedTypeItem(bounds, None),
+            inner: AssociatedTypeItem(bounds, self.ty.clean(cx)),
             visibility: self.vis.clean(cx),
             def_id: self.def_id,
             stability: stability::lookup(cx.tcx(), self.def_id).clean(cx),
diff --git a/src/test/run-pass/default-associated-types.rs b/src/test/run-pass/default-associated-types.rs
new file mode 100644
index 00000000000..b3def429b9b
--- /dev/null
+++ b/src/test/run-pass/default-associated-types.rs
@@ -0,0 +1,30 @@
+// 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.
+
+trait Foo<T> {
+    type Out = T;
+    fn foo(&self) -> Self::Out;
+}
+
+impl Foo<u32> for () {
+    fn foo(&self) -> u32 {
+        4u32
+    }
+}
+
+impl Foo<u64> for bool {
+    type Out = ();
+    fn foo(&self) {}
+}
+
+fn main() {
+    assert_eq!(<() as Foo<u32>>::foo(&()), 4u32);
+    assert_eq!(<bool as Foo<u64>>::foo(&true), ());
+}