about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-09-17 23:45:36 +0000
committerbors <bors@rust-lang.org>2014-09-17 23:45:36 +0000
commit9508faa2270a35595670cb3ca610ad17abff272d (patch)
treeb1c7c6d9c49f84e03b374b5b70cb0c9d0b60a7de /src/libsyntax
parent8067f4425d245a210c732a0333245fbe83190e89 (diff)
parent78a841810eb36e486ba68e6b9fa80e45d805cc4f (diff)
downloadrust-9508faa2270a35595670cb3ca610ad17abff272d.tar.gz
rust-9508faa2270a35595670cb3ca610ad17abff272d.zip
auto merge of #16377 : pcwalton/rust/associated-items, r=nikomatsakis
This is waiting on an RFC, but this basic functionality should be
straightforward. The implementation essentially desugars during type
collection and AST type conversion time into the parameter scheme we
have now.

r? @nikomatsakis 
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs34
-rw-r--r--src/libsyntax/ast_map/blocks.rs3
-rw-r--r--src/libsyntax/ast_map/mod.rs108
-rw-r--r--src/libsyntax/ast_util.rs57
-rw-r--r--src/libsyntax/config.rs4
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs5
-rw-r--r--src/libsyntax/feature_gate.rs26
-rw-r--r--src/libsyntax/fold.rs135
-rw-r--r--src/libsyntax/parse/parser.rs244
-rw-r--r--src/libsyntax/print/pprust.rs42
-rw-r--r--src/libsyntax/visit.rs27
11 files changed, 530 insertions, 155 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 5546f868ba0..eac158e664c 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -555,6 +555,18 @@ pub enum Expr_ {
     ExprParen(P<Expr>)
 }
 
+/// A "qualified path":
+///
+///     <Vec<T> as SomeTrait>::SomeAssociatedItem
+///      ^~~~~     ^~~~~~~~~   ^~~~~~~~~~~~~~~~~~
+///      for_type  trait_name  item_name
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct QPath {
+    pub for_type: P<Ty>,
+    pub trait_name: Path,
+    pub item_name: Ident,
+}
+
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub enum CaptureClause {
     CaptureByValue,
@@ -766,11 +778,31 @@ pub struct TypeMethod {
 pub enum TraitItem {
     RequiredMethod(TypeMethod),
     ProvidedMethod(P<Method>),
+    TypeTraitItem(P<AssociatedType>),
 }
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub enum ImplItem {
     MethodImplItem(P<Method>),
+    TypeImplItem(P<Typedef>),
+}
+
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct AssociatedType {
+    pub id: NodeId,
+    pub span: Span,
+    pub ident: Ident,
+    pub attrs: Vec<Attribute>,
+}
+
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct Typedef {
+    pub id: NodeId,
+    pub span: Span,
+    pub ident: Ident,
+    pub vis: Visibility,
+    pub attrs: Vec<Attribute>,
+    pub typ: P<Ty>,
 }
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
@@ -917,6 +949,8 @@ pub enum Ty_ {
     TyUnboxedFn(P<UnboxedFnTy>),
     TyTup(Vec<P<Ty>> ),
     TyPath(Path, Option<TyParamBounds>, NodeId), // for #7264; see above
+    /// A "qualified path", e.g. `<Vec<T> as SomeTrait>::SomeType`
+    TyQPath(P<QPath>),
     /// No-op; kept solely so that we can pretty-print faithfully
     TyParen(P<Ty>),
     TyTypeof(P<Expr>),
diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs
index 1400e494917..8280f34615f 100644
--- a/src/libsyntax/ast_map/blocks.rs
+++ b/src/libsyntax/ast_map/blocks.rs
@@ -207,6 +207,9 @@ impl<'a> FnLikeNode<'a> {
             ast_map::NodeImplItem(ii) => {
                 match *ii {
                     ast::MethodImplItem(ref m) => method(&**m),
+                    ast::TypeImplItem(_) => {
+                        fail!("impl method FnLikeNode that is not fn-like")
+                    }
                 }
             }
             ast_map::NodeExpr(e) => match e.node {
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index ed0b8700bf3..a5458461a8b 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -11,11 +11,11 @@
 use abi;
 use ast::*;
 use ast_util;
-use ast_util::PostExpansionMethod;
 use codemap::{DUMMY_SP, Span, Spanned};
 use fold::Folder;
 use parse::token;
 use print::pprust;
+use ptr::P;
 use visit::{mod, Visitor};
 
 use arena::TypedArena;
@@ -391,16 +391,20 @@ impl<'ast> Map<'ast> {
                             }
                         }
                     }
+                    TypeImplItem(ref t) => PathName(t.ident.name),
                 }
             },
             NodeTraitItem(tm) => match *tm {
                 RequiredMethod(ref m) => PathName(m.ident.name),
-                ProvidedMethod(ref m) => match m.node {
-                    MethDecl(ident, _, _, _, _, _, _, _) => {
-                        PathName(ident.name)
+                ProvidedMethod(ref m) => {
+                    match m.node {
+                        MethDecl(ident, _, _, _, _, _, _, _) => {
+                            PathName(ident.name)
+                        }
+                        MethMac(_) => fail!("no path elem for {:?}", node),
                     }
-                    MethMac(_) => fail!("no path elem for {:?}", node),
                 }
+                TypeTraitItem(ref m) => PathName(m.ident.name),
             },
             NodeVariant(v) => PathName(v.node.name.name),
             _ => fail!("no path elem for {:?}", node)
@@ -459,11 +463,13 @@ impl<'ast> Map<'ast> {
             NodeForeignItem(fi) => Some(fi.attrs.as_slice()),
             NodeTraitItem(ref tm) => match **tm {
                 RequiredMethod(ref type_m) => Some(type_m.attrs.as_slice()),
-                ProvidedMethod(ref m) => Some(m.attrs.as_slice())
+                ProvidedMethod(ref m) => Some(m.attrs.as_slice()),
+                TypeTraitItem(ref typ) => Some(typ.attrs.as_slice()),
             },
             NodeImplItem(ref ii) => {
                 match **ii {
                     MethodImplItem(ref m) => Some(m.attrs.as_slice()),
+                    TypeImplItem(ref t) => Some(t.attrs.as_slice()),
                 }
             }
             NodeVariant(ref v) => Some(v.node.attrs.as_slice()),
@@ -503,11 +509,13 @@ impl<'ast> Map<'ast> {
                 match *trait_method {
                     RequiredMethod(ref type_method) => type_method.span,
                     ProvidedMethod(ref method) => method.span,
+                    TypeTraitItem(ref typedef) => typedef.span,
                 }
             }
             Some(NodeImplItem(ref impl_item)) => {
                 match **impl_item {
                     MethodImplItem(ref method) => method.span,
+                    TypeImplItem(ref typedef) => typedef.span,
                 }
             }
             Some(NodeVariant(variant)) => variant.span,
@@ -633,6 +641,7 @@ impl Named for TraitItem {
         match *self {
             RequiredMethod(ref tm) => tm.ident.name,
             ProvidedMethod(ref m) => m.name(),
+            TypeTraitItem(ref at) => at.ident.name,
         }
     }
 }
@@ -640,6 +649,7 @@ impl Named for ImplItem {
     fn name(&self) -> Name {
         match *self {
             MethodImplItem(ref m) => m.name(),
+            TypeImplItem(ref td) => td.ident.name,
         }
     }
 }
@@ -712,10 +722,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         match i.node {
             ItemImpl(_, _, _, ref impl_items) => {
                 for impl_item in impl_items.iter() {
-                    let id = match *impl_item {
-                        MethodImplItem(ref m) => m.id
-                    };
-                    self.insert(id, NodeImplItem(impl_item));
+                    match *impl_item {
+                        MethodImplItem(ref m) => {
+                            self.insert(m.id, NodeImplItem(impl_item));
+                        }
+                        TypeImplItem(ref t) => {
+                            self.insert(t.id, NodeImplItem(impl_item));
+                        }
+                    }
                 }
             }
             ItemEnum(ref enum_definition, _) => {
@@ -737,13 +751,28 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
                     None => {}
                 }
             }
-            ItemTrait(_, _, _, ref methods) => {
-                for tm in methods.iter() {
-                    let id = match *tm {
-                        RequiredMethod(ref m) => m.id,
-                        ProvidedMethod(ref m) => m.id
-                    };
-                    self.insert(id, NodeTraitItem(tm));
+            ItemTrait(_, _, ref bounds, ref trait_items) => {
+                for b in bounds.iter() {
+                    match *b {
+                        TraitTyParamBound(ref t) => {
+                            self.insert(t.ref_id, NodeItem(i));
+                        }
+                        _ => {}
+                    }
+                }
+
+                for tm in trait_items.iter() {
+                    match *tm {
+                        RequiredMethod(ref m) => {
+                            self.insert(m.id, NodeTraitItem(tm));
+                        }
+                        ProvidedMethod(ref m) => {
+                            self.insert(m.id, NodeTraitItem(tm));
+                        }
+                        TypeTraitItem(ref typ) => {
+                            self.insert(typ.id, NodeTraitItem(tm));
+                        }
+                    }
                 }
             }
             _ => {}
@@ -892,6 +921,11 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
                 IITraitItem(fld.fold_ops.new_def_id(d),
                             RequiredMethod(fld.fold_type_method(ty_m)))
             }
+            TypeTraitItem(at) => {
+                IITraitItem(
+                    fld.fold_ops.new_def_id(d),
+                    TypeTraitItem(P(fld.fold_associated_type((*at).clone()))))
+            }
         },
         IIImplItem(d, m) => match m {
             MethodImplItem(m) => {
@@ -899,6 +933,10 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
                            MethodImplItem(fld.fold_method(m)
                                              .expect_one("expected one method")))
             }
+            TypeImplItem(t) => {
+                IIImplItem(fld.fold_ops.new_def_id(d),
+                           TypeImplItem(P(fld.fold_typedef((*t).clone()))))
+            }
         },
         IIForeign(i) => IIForeign(fld.fold_foreign_item(i))
     };
@@ -924,14 +962,16 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
         IITraitItem(_, ref trait_item) => {
             let trait_item_id = match *trait_item {
                 ProvidedMethod(ref m) => m.id,
-                RequiredMethod(ref m) => m.id
+                RequiredMethod(ref m) => m.id,
+                TypeTraitItem(ref ty) => ty.id,
             };
 
             collector.insert(trait_item_id, NodeTraitItem(trait_item));
         }
         IIImplItem(_, ref impl_item) => {
             let impl_item_id = match *impl_item {
-                MethodImplItem(ref m) => m.id
+                MethodImplItem(ref m) => m.id,
+                TypeImplItem(ref ti) => ti.id,
             };
 
             collector.insert(impl_item_id, NodeImplItem(impl_item));
@@ -1007,16 +1047,30 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String {
                                     pprust::mac_to_string(mac), id)
                     }
                 }
+                TypeImplItem(ref t) => {
+                    format!("typedef {} in {} (id={})",
+                            token::get_ident(t.ident),
+                            map.path_to_string(id),
+                            id)
+                }
             }
         }
-        Some(NodeTraitItem(ref ti)) => {
-            let ident = match **ti {
-                ProvidedMethod(ref m) => m.pe_ident(),
-                RequiredMethod(ref m) => m.ident
-            };
-            format!("method {} in {} (id={})",
-                    token::get_ident(ident),
-                    map.path_to_string(id), id)
+        Some(NodeTraitItem(ref tm)) => {
+            match **tm {
+                RequiredMethod(_) | ProvidedMethod(_) => {
+                    let m = ast_util::trait_item_to_ty_method(&**tm);
+                    format!("method {} in {} (id={})",
+                            token::get_ident(m.ident),
+                            map.path_to_string(id),
+                            id)
+                }
+                TypeTraitItem(ref t) => {
+                    format!("type item {} in {} (id={})",
+                            token::get_ident(t.ident),
+                            map.path_to_string(id),
+                            id)
+                }
+            }
         }
         Some(NodeVariant(ref variant)) => {
             format!("variant {} in {} (id={})",
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index becfe715f29..6d61c851476 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -213,6 +213,62 @@ pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: &Ty) -> Ident {
     token::gensym_ident(pretty.as_slice())
 }
 
+pub fn trait_method_to_ty_method(method: &Method) -> TypeMethod {
+    match method.node {
+        MethDecl(ident,
+                 ref generics,
+                 abi,
+                 ref explicit_self,
+                 fn_style,
+                 ref decl,
+                 _,
+                 vis) => {
+            TypeMethod {
+                ident: ident,
+                attrs: method.attrs.clone(),
+                fn_style: fn_style,
+                decl: (*decl).clone(),
+                generics: generics.clone(),
+                explicit_self: (*explicit_self).clone(),
+                id: method.id,
+                span: method.span,
+                vis: vis,
+                abi: abi,
+            }
+        },
+        MethMac(_) => fail!("expected non-macro method declaration")
+    }
+}
+
+/// extract a TypeMethod from a TraitItem. if the TraitItem is
+/// a default, pull out the useful fields to make a TypeMethod
+//
+// NB: to be used only after expansion is complete, and macros are gone.
+pub fn trait_item_to_ty_method(method: &TraitItem) -> TypeMethod {
+    match *method {
+        RequiredMethod(ref m) => (*m).clone(),
+        ProvidedMethod(ref m) => trait_method_to_ty_method(&**m),
+        TypeTraitItem(_) => {
+            fail!("trait_method_to_ty_method(): expected method but found \
+                   typedef")
+        }
+    }
+}
+
+pub fn split_trait_methods(trait_methods: &[TraitItem])
+                           -> (Vec<TypeMethod>, Vec<P<Method>> ) {
+    let mut reqd = Vec::new();
+    let mut provd = Vec::new();
+    for trt_method in trait_methods.iter() {
+        match *trt_method {
+            RequiredMethod(ref tm) => reqd.push((*tm).clone()),
+            ProvidedMethod(ref m) => provd.push((*m).clone()),
+            TypeTraitItem(_) => {}
+        }
+    };
+    (reqd, provd)
+}
+
 pub fn struct_field_visibility(field: ast::StructField) -> Visibility {
     match field.node.kind {
         ast::NamedField(_, v) | ast::UnnamedField(v) => v
@@ -471,6 +527,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
         match *tm {
             ast::RequiredMethod(ref m) => self.operation.visit_id(m.id),
             ast::ProvidedMethod(ref m) => self.operation.visit_id(m.id),
+            ast::TypeTraitItem(ref typ) => self.operation.visit_id(typ.id),
         }
         visit::walk_trait_item(self, tm);
     }
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index cb96cd911b5..3b250de8701 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -235,13 +235,15 @@ fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool {
 fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitItem) -> bool {
     match *meth {
         ast::RequiredMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
-        ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice())
+        ast::ProvidedMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
+        ast::TypeTraitItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()),
     }
 }
 
 fn impl_item_in_cfg(cx: &mut Context, impl_item: &ast::ImplItem) -> bool {
     match *impl_item {
         ast::MethodImplItem(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
+        ast::TypeImplItem(ref typ) => (cx.in_cfg)(typ.attrs.as_slice()),
     }
 }
 
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 6c7bbb2384c..7a7dbc54c9e 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -90,7 +90,10 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
             let mut parser = self.parser.borrow_mut();
             match parser.token {
                 EOF => break,
-                _ => ret.push(parser.parse_method(None))
+                _ => {
+                    let attrs = parser.parse_outer_attributes();
+                    ret.push(parser.parse_method(attrs, ast::Inherited))
+                }
             }
         }
         self.ensure_complete_parse(false);
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index e22e55193fc..5203ed0a073 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -68,6 +68,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
     ("import_shadowing", Active),
     ("advanced_slice_patterns", Active),
     ("tuple_indexing", Active),
+    ("associated_types", Active),
 
     // if you change this list without updating src/doc/rust.md, cmr will be sad
 
@@ -235,7 +236,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
                 }
             }
 
-            ast::ItemImpl(..) => {
+            ast::ItemImpl(_, _, _, ref items) => {
                 if attr::contains_name(i.attrs.as_slice(),
                                        "unsafe_destructor") {
                     self.gate_feature("unsafe_destructor",
@@ -244,6 +245,18 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
                                        many unsafe patterns and may be \
                                        removed in the future");
                 }
+
+                for item in items.iter() {
+                    match *item {
+                        ast::MethodImplItem(_) => {}
+                        ast::TypeImplItem(ref typedef) => {
+                            self.gate_feature("associated_types",
+                                              typedef.span,
+                                              "associated types are \
+                                               experimental")
+                        }
+                    }
+                }
             }
 
             _ => {}
@@ -252,6 +265,17 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
         visit::walk_item(self, i);
     }
 
+    fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
+        match *trait_item {
+            ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {}
+            ast::TypeTraitItem(ref ti) => {
+                self.gate_feature("associated_types",
+                                  ti.span,
+                                  "associated types are experimental")
+            }
+        }
+    }
+
     fn visit_mac(&mut self, macro: &ast::Mac) {
         let ast::MacInvocTT(ref path, _, _) = macro.node;
         let id = path.segments.last().unwrap().identifier;
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 4806c5fa7c0..3beba5bcda4 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -287,6 +287,15 @@ pub trait Folder {
         noop_fold_where_predicate(where_predicate, self)
     }
 
+    fn fold_typedef(&mut self, typedef: Typedef) -> Typedef {
+        noop_fold_typedef(typedef, self)
+    }
+
+    fn fold_associated_type(&mut self, associated_type: AssociatedType)
+                            -> AssociatedType {
+        noop_fold_associated_type(associated_type, self)
+    }
+
     fn new_id(&mut self, i: NodeId) -> NodeId {
         i
     }
@@ -414,6 +423,13 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
                         fld.fold_opt_bounds(bounds),
                         id)
             }
+            TyQPath(ref qpath) => {
+                TyQPath(P(QPath {
+                    for_type: fld.fold_ty(qpath.for_type.clone()),
+                    trait_name: fld.fold_path(qpath.trait_name.clone()),
+                    item_name: fld.fold_ident(qpath.item_name.clone()),
+                }))
+            }
             TyFixedLengthVec(ty, e) => {
                 TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
             }
@@ -735,6 +751,44 @@ pub fn noop_fold_where_predicate<T: Folder>(
     }
 }
 
+pub fn noop_fold_typedef<T>(t: Typedef, folder: &mut T)
+                            -> Typedef
+                            where T: Folder {
+    let new_id = folder.new_id(t.id);
+    let new_span = folder.new_span(t.span);
+    let new_attrs = t.attrs.iter().map(|attr| {
+        folder.fold_attribute((*attr).clone())
+    }).collect();
+    let new_ident = folder.fold_ident(t.ident);
+    let new_type = folder.fold_ty(t.typ);
+    ast::Typedef {
+        ident: new_ident,
+        typ: new_type,
+        id: new_id,
+        span: new_span,
+        vis: t.vis,
+        attrs: new_attrs,
+    }
+}
+
+pub fn noop_fold_associated_type<T>(at: AssociatedType, folder: &mut T)
+                                    -> AssociatedType
+                                    where T: Folder {
+    let new_id = folder.new_id(at.id);
+    let new_span = folder.new_span(at.span);
+    let new_ident = folder.fold_ident(at.ident);
+    let new_attrs = at.attrs
+                      .iter()
+                      .map(|attr| folder.fold_attribute((*attr).clone()))
+                      .collect();
+    ast::AssociatedType {
+        ident: new_ident,
+        attrs: new_attrs,
+        id: new_id,
+        span: new_span,
+    }
+}
+
 pub fn noop_fold_struct_def<T: Folder>(struct_def: P<StructDef>, fld: &mut T) -> P<StructDef> {
     struct_def.map(|StructDef {fields, ctor_id, super_struct, is_virtual}| StructDef {
         fields: fields.move_map(|f| fld.fold_struct_field(f)),
@@ -857,31 +911,59 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
             ItemStruct(struct_def, folder.fold_generics(generics))
         }
         ItemImpl(generics, ifce, ty, impl_items) => {
+            let mut new_impl_items = Vec::new();
+            for impl_item in impl_items.iter() {
+                match *impl_item {
+                    MethodImplItem(ref x) => {
+                        for method in folder.fold_method((*x).clone())
+                                            .move_iter() {
+                            new_impl_items.push(MethodImplItem(method))
+                        }
+                    }
+                    TypeImplItem(ref t) => {
+                        new_impl_items.push(TypeImplItem(
+                                P(folder.fold_typedef((**t).clone()))));
+                    }
+                }
+            }
+            let ifce = match ifce {
+                None => None,
+                Some(ref trait_ref) => {
+                    Some(folder.fold_trait_ref((*trait_ref).clone()))
+                }
+            };
             ItemImpl(folder.fold_generics(generics),
-                     ifce.map(|p| folder.fold_trait_ref(p)),
+                     ifce,
                      folder.fold_ty(ty),
-                     impl_items.into_iter().flat_map(|impl_item| match impl_item {
-                        MethodImplItem(x) => {
-                            folder.fold_method(x).into_iter().map(|x| MethodImplItem(x))
-                        }
-                     }).collect())
+                     new_impl_items)
         }
         ItemTrait(generics, unbound, bounds, methods) => {
             let bounds = folder.fold_bounds(bounds);
-            let methods = methods.into_iter().flat_map(|method| match method {
-                RequiredMethod(m) => {
-                    SmallVector::one(RequiredMethod(folder.fold_type_method(m))).into_iter()
-                }
-                ProvidedMethod(method) => {
-                    // the awkward collect/iter idiom here is because
-                    // even though an iter and a map satisfy the same trait bound,
-                    // they're not actually the same type, so the method arms
-                    // don't unify.
-                    let methods: SmallVector<ast::TraitItem> =
-                        folder.fold_method(method).into_iter()
-                        .map(|m| ProvidedMethod(m)).collect();
-                    methods.into_iter()
-                }
+            let methods = methods.into_iter().flat_map(|method| {
+                let r = match method {
+                    RequiredMethod(m) => {
+                            SmallVector::one(RequiredMethod(
+                                    folder.fold_type_method(m)))
+                                .move_iter()
+                    }
+                    ProvidedMethod(method) => {
+                        // the awkward collect/iter idiom here is because
+                        // even though an iter and a map satisfy the same
+                        // trait bound, they're not actually the same type, so
+                        // the method arms don't unify.
+                        let methods: SmallVector<ast::TraitItem> =
+                            folder.fold_method(method).move_iter()
+                            .map(|m| ProvidedMethod(m)).collect();
+                        methods.move_iter()
+                    }
+                    TypeTraitItem(at) => {
+                        SmallVector::one(TypeTraitItem(P(
+                                    folder.fold_associated_type(
+                                        (*at).clone()))))
+                            .move_iter()
+                    }
+                };
+                r
             }).collect();
             ItemTrait(folder.fold_generics(generics),
                       unbound,
@@ -893,7 +975,18 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
 }
 
 pub fn noop_fold_type_method<T: Folder>(m: TypeMethod, fld: &mut T) -> TypeMethod {
-    let TypeMethod {id, ident, attrs, fn_style, abi, decl, generics, explicit_self, vis, span} = m;
+    let TypeMethod {
+        id,
+        ident,
+        attrs,
+        fn_style,
+        abi,
+        decl,
+        generics,
+        explicit_self,
+        vis,
+        span
+    } = m;
     TypeMethod {
         id: fld.new_id(id),
         ident: fld.fold_ident(ident),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ea392c87723..ff4fd41fbd7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -11,11 +11,11 @@
 #![macro_escape]
 
 use abi;
-use ast::{BareFnTy, ClosureTy};
+use ast::{AssociatedType, BareFnTy, ClosureTy};
 use ast::{RegionTyParamBound, TraitTyParamBound};
 use ast::{ProvidedMethod, Public, FnStyle};
 use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
-use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
+use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, Block};
 use ast::{BlockCheckMode, UnBox};
 use ast::{CaptureByRef, CaptureByValue, CaptureClause};
 use ast::{Crate, CrateConfig, Decl, DeclItem};
@@ -42,7 +42,7 @@ use ast::{MatchSeq, MatchTok, Method, MutTy, BiMul, Mutability};
 use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
 use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct};
 use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle};
-use ast::{BiRem, RequiredMethod};
+use ast::{QPath, RequiredMethod};
 use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl};
 use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
 use ast::{StructVariantKind, BiSub};
@@ -52,10 +52,10 @@ use ast::{TokenTree, TraitItem, TraitRef, TTDelim, TTSeq, TTTok};
 use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox};
 use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
 use ast::{TyTypeof, TyInfer, TypeMethod};
-use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyRptr};
-use ast::{TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
-use ast::{UnboxedClosureKind, UnboxedFnTy, UnboxedFnTyParamBound};
-use ast::{UnnamedField, UnsafeBlock};
+use ast::{TyNil, TyParam, TyParamBound, TyParen, TyPath, TyPtr, TyQPath};
+use ast::{TyRptr, TyTup, TyU32, TyUnboxedFn, TyUniq, TyVec, UnUniq};
+use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind};
+use ast::{UnboxedFnTy, UnboxedFnTyParamBound, UnnamedField, UnsafeBlock};
 use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
 use ast::{Visibility, WhereClause, WherePredicate};
@@ -1235,86 +1235,125 @@ impl<'a> Parser<'a> {
         (decl, lifetime_defs)
     }
 
-    /// Parse the methods in a trait declaration
-    pub fn parse_trait_methods(&mut self) -> Vec<TraitItem> {
+    /// Parses `type Foo;` in a trait declaration only. The `type` keyword has
+    /// already been parsed.
+    fn parse_associated_type(&mut self, attrs: Vec<Attribute>)
+                             -> AssociatedType {
+        let lo = self.span.lo;
+        let ident = self.parse_ident();
+        let hi = self.span.hi;
+        self.expect(&token::SEMI);
+        AssociatedType {
+            id: ast::DUMMY_NODE_ID,
+            span: mk_sp(lo, hi),
+            ident: ident,
+            attrs: attrs,
+        }
+    }
+
+    /// Parses `type Foo = TYPE;` in an implementation declaration only. The
+    /// `type` keyword has already been parsed.
+    fn parse_typedef(&mut self, attrs: Vec<Attribute>, vis: Visibility)
+                     -> Typedef {
+        let lo = self.span.lo;
+        let ident = self.parse_ident();
+        self.expect(&token::EQ);
+        let typ = self.parse_ty(true);
+        let hi = self.span.hi;
+        self.expect(&token::SEMI);
+        Typedef {
+            id: ast::DUMMY_NODE_ID,
+            span: mk_sp(lo, hi),
+            ident: ident,
+            vis: vis,
+            attrs: attrs,
+            typ: typ,
+        }
+    }
+
+    /// Parse the items in a trait declaration
+    pub fn parse_trait_items(&mut self) -> Vec<TraitItem> {
         self.parse_unspanned_seq(
             &token::LBRACE,
             &token::RBRACE,
             seq_sep_none(),
             |p| {
             let attrs = p.parse_outer_attributes();
-            let lo = p.span.lo;
-
-            // NB: at the moment, trait methods are public by default; this
-            // could change.
-            let vis = p.parse_visibility();
-            let abi = if p.eat_keyword(keywords::Extern) {
-                p.parse_opt_abi().unwrap_or(abi::C)
-            } else if attr::contains_name(attrs.as_slice(),
-                                          "rust_call_abi_hack") {
-                // FIXME(stage0, pcwalton): Remove this awful hack after a
-                // snapshot, and change to `extern "rust-call" fn`.
-                abi::RustCall
+
+            if p.eat_keyword(keywords::Type) {
+                TypeTraitItem(P(p.parse_associated_type(attrs)))
             } else {
-                abi::Rust
-            };
-            let style = p.parse_fn_style();
-            let ident = p.parse_ident();
+                let lo = p.span.lo;
 
-            let mut generics = p.parse_generics();
+                let vis = p.parse_visibility();
+                let abi = if p.eat_keyword(keywords::Extern) {
+                    p.parse_opt_abi().unwrap_or(abi::C)
+                } else if attr::contains_name(attrs.as_slice(),
+                                              "rust_call_abi_hack") {
+                    // FIXME(stage0, pcwalton): Remove this awful hack after a
+                    // snapshot, and change to `extern "rust-call" fn`.
+                    abi::RustCall
+                } else {
+                    abi::Rust
+                };
 
-            let (explicit_self, d) = p.parse_fn_decl_with_self(|p| {
-                // This is somewhat dubious; We don't want to allow argument
-                // names to be left off if there is a definition...
-                p.parse_arg_general(false)
-            });
+                let style = p.parse_fn_style();
+                let ident = p.parse_ident();
+                let mut generics = p.parse_generics();
 
-            p.parse_where_clause(&mut generics);
+                let (explicit_self, d) = p.parse_fn_decl_with_self(|p| {
+                    // This is somewhat dubious; We don't want to allow
+                    // argument names to be left off if there is a
+                    // definition...
+                    p.parse_arg_general(false)
+                });
 
-            let hi = p.last_span.hi;
-            match p.token {
-              token::SEMI => {
-                p.bump();
-                debug!("parse_trait_methods(): parsing required method");
-                RequiredMethod(TypeMethod {
-                    ident: ident,
-                    attrs: attrs,
-                    fn_style: style,
-                    decl: d,
-                    generics: generics,
-                    abi: abi,
-                    explicit_self: explicit_self,
-                    id: ast::DUMMY_NODE_ID,
-                    span: mk_sp(lo, hi),
-                    vis: vis,
-                })
-              }
-              token::LBRACE => {
-                debug!("parse_trait_methods(): parsing provided method");
-                let (inner_attrs, body) =
-                    p.parse_inner_attrs_and_block();
-                let mut attrs = attrs;
-                attrs.extend(inner_attrs.into_iter());
-                ProvidedMethod(P(ast::Method {
-                    attrs: attrs,
-                    id: ast::DUMMY_NODE_ID,
-                    span: mk_sp(lo, hi),
-                    node: ast::MethDecl(ident,
-                                        generics,
-                                        abi,
-                                        explicit_self,
-                                        style,
-                                        d,
-                                        body,
-                                        vis)
-                }))
-              }
+                p.parse_where_clause(&mut generics);
+
+                let hi = p.last_span.hi;
+                match p.token {
+                  token::SEMI => {
+                    p.bump();
+                    debug!("parse_trait_methods(): parsing required method");
+                    RequiredMethod(TypeMethod {
+                        ident: ident,
+                        attrs: attrs,
+                        fn_style: style,
+                        decl: d,
+                        generics: generics,
+                        abi: abi,
+                        explicit_self: explicit_self,
+                        id: ast::DUMMY_NODE_ID,
+                        span: mk_sp(lo, hi),
+                        vis: vis,
+                    })
+                  }
+                  token::LBRACE => {
+                    debug!("parse_trait_methods(): parsing provided method");
+                    let (inner_attrs, body) =
+                        p.parse_inner_attrs_and_block();
+                    let attrs = attrs.append(inner_attrs.as_slice());
+                    ProvidedMethod(P(ast::Method {
+                        attrs: attrs,
+                        id: ast::DUMMY_NODE_ID,
+                        span: mk_sp(lo, hi),
+                        node: ast::MethDecl(ident,
+                                            generics,
+                                            abi,
+                                            explicit_self,
+                                            style,
+                                            d,
+                                            body,
+                                            vis)
+                    }))
+                  }
 
-              _ => {
-                  let token_str = p.this_token_to_string();
-                  p.fatal((format!("expected `;` or `{{`, found `{}`",
-                                   token_str)).as_slice())
-              }
+                  _ => {
+                      let token_str = p.this_token_to_string();
+                      p.fatal((format!("expected `;` or `{{`, found `{}`",
+                                       token_str)).as_slice())
+                  }
+                }
             }
         })
     }
@@ -1455,12 +1494,11 @@ impl<'a> Parser<'a> {
         } else if self.token_is_closure_keyword() ||
                 self.token == token::BINOP(token::OR) ||
                 self.token == token::OROR ||
-                self.token == token::LT {
+                (self.token == token::LT &&
+                 self.look_ahead(1, |t| {
+                     *t == token::GT || Parser::token_is_lifetime(t)
+                 })) {
             // CLOSURE
-            //
-            // FIXME(pcwalton): Eventually `token::LT` will not unambiguously
-            // introduce a closure, once procs can have lifetime bounds. We
-            // will need to refactor the grammar a little bit at that point.
 
             self.parse_ty_closure()
         } else if self.eat_keyword(keywords::Typeof) {
@@ -1472,6 +1510,20 @@ impl<'a> Parser<'a> {
             TyTypeof(e)
         } else if self.eat_keyword(keywords::Proc) {
             self.parse_proc_type()
+        } else if self.token == token::LT {
+            // QUALIFIED PATH
+            self.bump();
+            let for_type = self.parse_ty(true);
+            self.expect_keyword(keywords::As);
+            let trait_name = self.parse_path(LifetimeAndTypesWithoutColons);
+            self.expect(&token::GT);
+            self.expect(&token::MOD_SEP);
+            let item_name = self.parse_ident();
+            TyQPath(P(QPath {
+                for_type: for_type,
+                trait_name: trait_name.path,
+                item_name: item_name,
+            }))
         } else if self.token == token::MOD_SEP
             || is_ident_or_path(&self.token) {
             // NAMED TYPE
@@ -2071,7 +2123,7 @@ impl<'a> Parser<'a> {
                     }
                 }
                 hi = self.last_span.hi;
-            },
+            }
             _ => {
                 if self.eat_keyword(keywords::Ref) {
                     return self.parse_lambda_expr(CaptureByRef);
@@ -4215,14 +4267,9 @@ impl<'a> Parser<'a> {
 
     /// Parse a method in a trait impl, starting with `attrs` attributes.
     pub fn parse_method(&mut self,
-                        already_parsed_attrs: Option<Vec<Attribute>>)
+                        attrs: Vec<Attribute>,
+                        visa: Visibility)
                         -> P<Method> {
-        let next_attrs = self.parse_outer_attributes();
-        let attrs = match already_parsed_attrs {
-            Some(mut a) => { a.push_all_move(next_attrs); a }
-            None => next_attrs
-        };
-
         let lo = self.span.lo;
 
         // code copied from parse_macro_use_or_failure... abstraction!
@@ -4251,7 +4298,6 @@ impl<'a> Parser<'a> {
                                                              self.span.hi) };
                 (ast::MethMac(m), self.span.hi, attrs)
             } else {
-                let visa = self.parse_visibility();
                 let abi = if self.eat_keyword(keywords::Extern) {
                     self.parse_opt_abi().unwrap_or(abi::C)
                 } else if attr::contains_name(attrs.as_slice(),
@@ -4302,18 +4348,28 @@ impl<'a> Parser<'a> {
 
         self.parse_where_clause(&mut tps);
 
-        let meths = self.parse_trait_methods();
+        let meths = self.parse_trait_items();
         (ident, ItemTrait(tps, sized, bounds, meths), None)
     }
 
     fn parse_impl_items(&mut self) -> (Vec<ImplItem>, Vec<Attribute>) {
         let mut impl_items = Vec::new();
         self.expect(&token::LBRACE);
-        let (inner_attrs, next) = self.parse_inner_attrs_and_next();
-        let mut method_attrs = Some(next);
+        let (inner_attrs, mut method_attrs) =
+            self.parse_inner_attrs_and_next();
         while !self.eat(&token::RBRACE) {
-            impl_items.push(MethodImplItem(self.parse_method(method_attrs)));
-            method_attrs = None;
+            method_attrs.push_all_move(self.parse_outer_attributes());
+            let vis = self.parse_visibility();
+            if self.eat_keyword(keywords::Type) {
+                impl_items.push(TypeImplItem(P(self.parse_typedef(
+                            method_attrs,
+                            vis))))
+            } else {
+                impl_items.push(MethodImplItem(self.parse_method(
+                            method_attrs,
+                            vis)));
+            }
+            method_attrs = self.parse_outer_attributes();
         }
         (impl_items, inner_attrs)
     }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index d0df95d711e..0ae5303641b 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -9,10 +9,11 @@
 // except according to those terms.
 
 use abi;
-use ast::{FnMutUnboxedClosureKind, FnOnceUnboxedClosureKind};
-use ast::{FnUnboxedClosureKind, MethodImplItem};
-use ast::{RegionTyParamBound, TraitTyParamBound, UnboxedClosureKind};
-use ast::{UnboxedFnTyParamBound, RequiredMethod, ProvidedMethod};
+use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
+use ast::{FnOnceUnboxedClosureKind};
+use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound};
+use ast::{RequiredMethod, ProvidedMethod, TypeImplItem, TypeTraitItem};
+use ast::{UnboxedClosureKind, UnboxedFnTyParamBound};
 use ast;
 use ast_util;
 use owned_slice::OwnedSlice;
@@ -660,6 +661,16 @@ impl<'a> State<'a> {
             ast::TyPath(ref path, ref bounds, _) => {
                 try!(self.print_bounded_path(path, bounds));
             }
+            ast::TyQPath(ref qpath) => {
+                try!(word(&mut self.s, "<"));
+                try!(self.print_type(&*qpath.for_type));
+                try!(space(&mut self.s));
+                try!(self.word_space("as"));
+                try!(self.print_path(&qpath.trait_name, false));
+                try!(word(&mut self.s, ">"));
+                try!(word(&mut self.s, "::"));
+                try!(self.print_ident(qpath.item_name));
+            }
             ast::TyFixedLengthVec(ref ty, ref v) => {
                 try!(word(&mut self.s, "["));
                 try!(self.print_type(&**ty));
@@ -708,6 +719,22 @@ impl<'a> State<'a> {
         }
     }
 
+    fn print_associated_type(&mut self, typedef: &ast::AssociatedType)
+                             -> IoResult<()> {
+        try!(self.word_space("type"));
+        try!(self.print_ident(typedef.ident));
+        word(&mut self.s, ";")
+    }
+
+    fn print_typedef(&mut self, typedef: &ast::Typedef) -> IoResult<()> {
+        try!(self.word_space("type"));
+        try!(self.print_ident(typedef.ident));
+        try!(space(&mut self.s));
+        try!(self.word_space("="));
+        try!(self.print_type(&*typedef.typ));
+        word(&mut self.s, ";")
+    }
+
     /// Pretty-print an item
     pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> {
         try!(self.hardbreak_if_not_bol());
@@ -825,6 +852,9 @@ impl<'a> State<'a> {
                         ast::MethodImplItem(ref meth) => {
                             try!(self.print_method(&**meth));
                         }
+                        ast::TypeImplItem(ref typ) => {
+                            try!(self.print_typedef(&**typ));
+                        }
                     }
                 }
                 try!(self.bclose(item.span));
@@ -1071,13 +1101,15 @@ impl<'a> State<'a> {
                               m: &ast::TraitItem) -> IoResult<()> {
         match *m {
             RequiredMethod(ref ty_m) => self.print_ty_method(ty_m),
-            ProvidedMethod(ref m) => self.print_method(&**m)
+            ProvidedMethod(ref m) => self.print_method(&**m),
+            TypeTraitItem(ref t) => self.print_associated_type(&**t),
         }
     }
 
     pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> IoResult<()> {
         match *ii {
             MethodImplItem(ref m) => self.print_method(&**m),
+            TypeImplItem(ref td) => self.print_typedef(&**td),
         }
     }
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 30a38e28729..d425c60f4c9 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -116,12 +116,19 @@ pub trait Visitor<'v> {
     fn visit_attribute(&mut self, _attr: &'v Attribute) {}
 }
 
-pub fn walk_inlined_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v InlinedItem) {
+pub fn walk_inlined_item<'v,V>(visitor: &mut V, item: &'v InlinedItem)
+                         where V: Visitor<'v> {
     match *item {
         IIItem(ref i) => visitor.visit_item(&**i),
         IIForeign(ref i) => visitor.visit_foreign_item(&**i),
         IITraitItem(_, ref ti) => visitor.visit_trait_item(ti),
-        IIImplItem(_, MethodImplItem(ref m)) => walk_method_helper(visitor, &**m)
+        IIImplItem(_, MethodImplItem(ref m)) => {
+            walk_method_helper(visitor, &**m)
+        }
+        IIImplItem(_, TypeImplItem(ref typedef)) => {
+            visitor.visit_ident(typedef.span, typedef.ident);
+            visitor.visit_ty(&*typedef.typ);
+        }
     }
 }
 
@@ -248,6 +255,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
                     MethodImplItem(ref method) => {
                         walk_method_helper(visitor, &**method)
                     }
+                    TypeImplItem(ref typedef) => {
+                        visitor.visit_ident(typedef.span, typedef.ident);
+                        visitor.visit_ty(&*typedef.typ);
+                    }
                 }
             }
         }
@@ -366,6 +377,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
                 None => { }
             }
         }
+        TyQPath(ref qpath) => {
+            visitor.visit_ty(&*qpath.for_type);
+            visitor.visit_path(&qpath.trait_name, typ.id);
+            visitor.visit_ident(typ.span, qpath.item_name);
+        }
         TyFixedLengthVec(ref ty, ref expression) => {
             visitor.visit_ty(&**ty);
             visitor.visit_expr(&**expression)
@@ -573,10 +589,11 @@ pub fn walk_ty_method<'v, V: Visitor<'v>>(visitor: &mut V, method_type: &'v Type
 
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_method: &'v TraitItem) {
     match *trait_method {
-        RequiredMethod(ref method_type) => {
-            visitor.visit_ty_method(method_type)
-        }
+        RequiredMethod(ref method_type) => visitor.visit_ty_method(method_type),
         ProvidedMethod(ref method) => walk_method_helper(visitor, &**method),
+        TypeTraitItem(ref associated_type) => {
+            visitor.visit_ident(associated_type.span, associated_type.ident)
+        }
     }
 }