about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/astencode.rs7
-rw-r--r--src/librustc/middle/privacy.rs4
-rw-r--r--src/librustc/middle/resolve.rs62
-rw-r--r--src/librustc/middle/stability.rs2
-rw-r--r--src/librustc/middle/subst.rs119
-rw-r--r--src/librustc/middle/traits/select.rs4
-rw-r--r--src/librustc/middle/trans/meth.rs27
-rw-r--r--src/librustc/middle/ty.rs27
-rw-r--r--src/librustc/middle/typeck/astconv.rs51
-rw-r--r--src/librustc/middle/typeck/collect.rs427
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs11
-rw-r--r--src/librustc/util/ppaux.rs66
-rw-r--r--src/librustdoc/clean/mod.rs6
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/ast_map/mod.rs14
-rw-r--r--src/libsyntax/ast_util.rs2
-rw-r--r--src/libsyntax/feature_gate.rs2
-rw-r--r--src/libsyntax/fold.rs11
-rw-r--r--src/libsyntax/parse/parser.rs11
-rw-r--r--src/libsyntax/print/pprust.rs44
-rw-r--r--src/libsyntax/visit.rs3
-rw-r--r--src/test/compile-fail/associated-types-unsized.rs24
-rw-r--r--src/test/compile-fail/variance-regions-direct.rs14
-rw-r--r--src/test/compile-fail/variance-regions-indirect.rs10
-rw-r--r--src/test/compile-fail/variance-trait-object-bound.rs2
25 files changed, 520 insertions, 434 deletions
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 41ed7fcf01a..0074c15defb 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -79,7 +79,7 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
         e::IIForeignRef(i) => i.id,
         e::IITraitItemRef(_, &ast::ProvidedMethod(ref m)) => m.id,
         e::IITraitItemRef(_, &ast::RequiredMethod(ref m)) => m.id,
-        e::IITraitItemRef(_, &ast::TypeTraitItem(ref ti)) => ti.id,
+        e::IITraitItemRef(_, &ast::TypeTraitItem(ref ti)) => ti.ty_param.id,
         e::IIImplItemRef(_, &ast::MethodImplItem(ref m)) => m.id,
         e::IIImplItemRef(_, &ast::TypeImplItem(ref ti)) => ti.id,
     };
@@ -154,7 +154,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
                 match *ti {
                     ast::ProvidedMethod(ref m) => m.pe_ident(),
                     ast::RequiredMethod(ref ty_m) => ty_m.ident,
-                    ast::TypeTraitItem(ref ti) => ti.ident,
+                    ast::TypeTraitItem(ref ti) => ti.ty_param.ident,
                 }
             },
             ast::IIImplItem(_, ref m) => {
@@ -709,8 +709,9 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
     {
         let types = self.read_to_vec(|this| Ok(f(this))).unwrap();
         let selfs = self.read_to_vec(|this| Ok(f(this))).unwrap();
+        let assocs = self.read_to_vec(|this| Ok(f(this))).unwrap();
         let fns = self.read_to_vec(|this| Ok(f(this))).unwrap();
-        VecPerParamSpace::new(types, selfs, fns)
+        VecPerParamSpace::new(types, selfs, assocs, fns)
     }
 
     fn read_vtable_res_with_key(&mut self,
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 2256bd71e65..4fbffa2a819 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -296,8 +296,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
                             self.exported_items.insert(m.id);
                         }
                         ast::TypeTraitItem(ref t) => {
-                            debug!("typedef {}", t.id);
-                            self.exported_items.insert(t.id);
+                            debug!("typedef {}", t.ty_param.id);
+                            self.exported_items.insert(t.ty_param.id);
                         }
                     }
                 }
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 3ac8ae1b0f4..ed7d9296c70 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -1564,19 +1564,19 @@ impl<'a> Resolver<'a> {
                         }
                         ast::TypeTraitItem(ref associated_type) => {
                             let def = DefAssociatedTy(local_def(
-                                    associated_type.id));
+                                    associated_type.ty_param.id));
 
                             let name_bindings =
-                                self.add_child(associated_type.ident.name,
+                                self.add_child(associated_type.ty_param.ident.name,
                                                module_parent.clone(),
                                                ForbidDuplicateTypesAndValues,
-                                               associated_type.span);
+                                               associated_type.ty_param.span);
                             // NB: not IMPORTABLE
                             name_bindings.define_type(def,
-                                                      associated_type.span,
+                                                      associated_type.ty_param.span,
                                                       PUBLIC);
 
-                            (associated_type.ident.name, TypeTraitItemKind)
+                            (associated_type.ty_param.ident.name, TypeTraitItemKind)
                         }
                     };
 
@@ -4223,7 +4223,7 @@ impl<'a> Resolver<'a> {
                                             impl_items.as_slice());
             }
 
-            ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => {
+            ItemTrait(ref generics, ref unbound, ref bounds, ref trait_items) => {
                 // Create a new rib for the self type.
                 let mut self_type_rib = Rib::new(ItemRibKind);
 
@@ -4251,13 +4251,13 @@ impl<'a> Resolver<'a> {
                         _ => {}
                     }
 
-                    for method in (*methods).iter() {
-                        // Create a new rib for the method-specific type
+                    for trait_item in (*trait_items).iter() {
+                        // Create a new rib for the trait_item-specific type
                         // parameters.
                         //
                         // FIXME #4951: Do we need a node ID here?
 
-                        match *method {
+                        match *trait_item {
                           ast::RequiredMethod(ref ty_m) => {
                             this.with_type_parameter_rib
                                 (HasTypeParameters(&ty_m.generics,
@@ -4292,8 +4292,9 @@ impl<'a> Resolver<'a> {
                                                                 ProvidedMethod(m.id)),
                                                   &**m)
                           }
-                          ast::TypeTraitItem(_) => {
-                              visit::walk_trait_item(this, method);
+                          ast::TypeTraitItem(ref data) => {
+                              this.resolve_type_parameter(&data.ty_param);
+                              visit::walk_trait_item(this, trait_item);
                           }
                         }
                     }
@@ -4482,20 +4483,25 @@ impl<'a> Resolver<'a> {
     fn resolve_type_parameters(&mut self,
                                type_parameters: &OwnedSlice<TyParam>) {
         for type_parameter in type_parameters.iter() {
-            for bound in type_parameter.bounds.iter() {
-                self.resolve_type_parameter_bound(type_parameter.id, bound,
-                                                  TraitBoundingTypeParameter);
-            }
-            match &type_parameter.unbound {
-                &Some(ref unbound) =>
-                    self.resolve_type_parameter_bound(
-                        type_parameter.id, unbound, TraitBoundingTypeParameter),
-                &None => {}
-            }
-            match type_parameter.default {
-                Some(ref ty) => self.resolve_type(&**ty),
-                None => {}
-            }
+            self.resolve_type_parameter(type_parameter);
+        }
+    }
+
+    fn resolve_type_parameter(&mut self,
+                              type_parameter: &TyParam) {
+        for bound in type_parameter.bounds.iter() {
+            self.resolve_type_parameter_bound(type_parameter.id, bound,
+                                              TraitBoundingTypeParameter);
+        }
+        match &type_parameter.unbound {
+            &Some(ref unbound) =>
+                self.resolve_type_parameter_bound(
+                    type_parameter.id, unbound, TraitBoundingTypeParameter),
+            &None => {}
+        }
+        match type_parameter.default {
+            Some(ref ty) => self.resolve_type(&**ty),
+            None => {}
         }
     }
 
@@ -4582,14 +4588,14 @@ impl<'a> Resolver<'a> {
                         self.resolve_error(trait_reference.path.span,
                                            format!("`{}` is not a trait",
                                                    self.path_names_to_string(
-                                                        &trait_reference.path)));
+                                                       &trait_reference.path)));
 
                         // If it's a typedef, give a note
                         match def {
                             DefTy(..) => {
                                 self.session.span_note(
-                                                trait_reference.path.span,
-                                                format!("`type` aliases cannot \
+                                    trait_reference.path.span,
+                                    format!("`type` aliases cannot \
                                                         be used for traits")
                                                         .as_slice());
                             }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 9cac97dc659..7f6a73c83fa 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -86,7 +86,7 @@ impl<'v> Visitor<'v> for Annotator {
                 }
             }
 
-            TypeTraitItem(ref typedef) => (typedef.id, &typedef.attrs),
+            TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs),
         };
         self.annotate(id, attrs, |v| visit::walk_trait_item(v, t));
     }
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index bec02c736ad..a29f99236e0 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -56,17 +56,18 @@ impl Substs {
                     r: Vec<ty::Region>)
                     -> Substs
     {
-        Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()),
-                    VecPerParamSpace::new(r, Vec::new(), Vec::new()))
+        Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new(), Vec::new()),
+                    VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new()))
     }
 
     pub fn new_trait(t: Vec<ty::t>,
                      r: Vec<ty::Region>,
+                     a: Vec<ty::t>,
                      s: ty::t)
                     -> Substs
     {
-        Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()),
-                    VecPerParamSpace::new(r, Vec::new(), Vec::new()))
+        Substs::new(VecPerParamSpace::new(t, vec!(s), a, Vec::new()),
+                    VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new()))
     }
 
     pub fn erased(t: VecPerParamSpace<ty::t>) -> Substs
@@ -170,21 +171,23 @@ impl RegionSubsts {
 #[deriving(PartialOrd, Ord, PartialEq, Eq,
            Clone, Hash, Encodable, Decodable, Show)]
 pub enum ParamSpace {
-    TypeSpace, // Type parameters attached to a type definition, trait, or impl
-    SelfSpace, // Self parameter on a trait
-    FnSpace,   // Type parameters attached to a method or fn
+    TypeSpace,  // Type parameters attached to a type definition, trait, or impl
+    SelfSpace,  // Self parameter on a trait
+    AssocSpace, // Assoc types defined in a trait/impl
+    FnSpace,    // Type parameters attached to a method or fn
 }
 
 impl ParamSpace {
-    pub fn all() -> [ParamSpace, ..3] {
-        [TypeSpace, SelfSpace, FnSpace]
+    pub fn all() -> [ParamSpace, ..4] {
+        [TypeSpace, SelfSpace, AssocSpace, FnSpace]
     }
 
     pub fn to_uint(self) -> uint {
         match self {
             TypeSpace => 0,
             SelfSpace => 1,
-            FnSpace => 2,
+            AssocSpace => 2,
+            FnSpace => 3,
         }
     }
 
@@ -192,7 +195,8 @@ impl ParamSpace {
         match u {
             0 => TypeSpace,
             1 => SelfSpace,
-            2 => FnSpace,
+            2 => AssocSpace,
+            3 => FnSpace,
             _ => panic!("Invalid ParamSpace: {}", u)
         }
     }
@@ -212,14 +216,27 @@ pub struct VecPerParamSpace<T> {
     // Here is how the representation corresponds to the abstraction
     // i.e. the "abstraction function" AF:
     //
-    // AF(self) = (self.content.slice_to(self.type_limit),
-    //             self.content.slice(self.type_limit, self.self_limit),
-    //             self.content.slice_from(self.self_limit))
+    // AF(self) = (self.content[..self.type_limit],
+    //             self.content[self.type_limit..self.self_limit],
+    //             self.content[self.self_limit..self.assoc_limit],
+    //             self.content[self.assoc_limit..])
     type_limit: uint,
     self_limit: uint,
+    assoc_limit: uint,
     content: Vec<T>,
 }
 
+/**
+ * The `split` function converts one `VecPerParamSpace` into this
+ * `SeparateVecsPerParamSpace` structure.
+ */
+pub struct SeparateVecsPerParamSpace<T> {
+    pub types: Vec<T>,
+    pub selfs: Vec<T>,
+    pub assocs: Vec<T>,
+    pub fns: Vec<T>,
+}
+
 impl<T:fmt::Show> fmt::Show for VecPerParamSpace<T> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         try!(write!(fmt, "VecPerParamSpace {{"));
@@ -236,7 +253,8 @@ impl<T> VecPerParamSpace<T> {
         match space {
             TypeSpace => (0, self.type_limit),
             SelfSpace => (self.type_limit, self.self_limit),
-            FnSpace => (self.self_limit, self.content.len()),
+            AssocSpace => (self.self_limit, self.assoc_limit),
+            FnSpace => (self.assoc_limit, self.content.len()),
         }
     }
 
@@ -244,6 +262,7 @@ impl<T> VecPerParamSpace<T> {
         VecPerParamSpace {
             type_limit: 0,
             self_limit: 0,
+            assoc_limit: 0,
             content: Vec::new()
         }
     }
@@ -254,26 +273,33 @@ impl<T> VecPerParamSpace<T> {
 
     /// `t` is the type space.
     /// `s` is the self space.
+    /// `a` is the assoc space.
     /// `f` is the fn space.
-    pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
+    pub fn new(t: Vec<T>, s: Vec<T>, a: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
         let type_limit = t.len();
-        let self_limit = t.len() + s.len();
+        let self_limit = type_limit + s.len();
+        let assoc_limit = self_limit + a.len();
+
         let mut content = t;
         content.extend(s.into_iter());
+        content.extend(a.into_iter());
         content.extend(f.into_iter());
+
         VecPerParamSpace {
             type_limit: type_limit,
             self_limit: self_limit,
+            assoc_limit: assoc_limit,
             content: content,
         }
     }
 
-    fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint)
+    fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint, assoc_limit: uint)
                     -> VecPerParamSpace<T>
     {
         VecPerParamSpace {
             type_limit: type_limit,
             self_limit: self_limit,
+            assoc_limit: assoc_limit,
             content: content,
         }
     }
@@ -285,9 +311,10 @@ impl<T> VecPerParamSpace<T> {
     pub fn push(&mut self, space: ParamSpace, value: T) {
         let (_, limit) = self.limits(space);
         match space {
-            TypeSpace => { self.type_limit += 1; self.self_limit += 1; }
-            SelfSpace => { self.self_limit += 1; }
-            FnSpace   => {}
+            TypeSpace => { self.type_limit += 1; self.self_limit += 1; self.assoc_limit += 1; }
+            SelfSpace => { self.self_limit += 1; self.assoc_limit += 1; }
+            AssocSpace => { self.assoc_limit += 1; }
+            FnSpace => { }
         }
         self.content.insert(limit, value);
     }
@@ -298,9 +325,10 @@ impl<T> VecPerParamSpace<T> {
             None
         } else {
             match space {
-                TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; }
-                SelfSpace => { self.self_limit -= 1; }
-                FnSpace   => {}
+                TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; self.assoc_limit -= 1; }
+                SelfSpace => { self.self_limit -= 1; self.assoc_limit -= 1; }
+                AssocSpace => { self.assoc_limit -= 1; }
+                FnSpace => {}
             }
             self.content.remove(limit - 1)
         }
@@ -386,35 +414,35 @@ impl<T> VecPerParamSpace<T> {
         let result = self.iter().map(pred).collect();
         VecPerParamSpace::new_internal(result,
                                        self.type_limit,
-                                       self.self_limit)
+                                       self.self_limit,
+                                       self.assoc_limit)
     }
 
     pub fn map_move<U>(self, pred: |T| -> U) -> VecPerParamSpace<U> {
-        let (t, s, f) = self.split();
+        let SeparateVecsPerParamSpace {
+            types: t,
+            selfs: s,
+            assocs: a,
+            fns: f
+        } = self.split();
+
         VecPerParamSpace::new(t.into_iter().map(|p| pred(p)).collect(),
                               s.into_iter().map(|p| pred(p)).collect(),
+                              a.into_iter().map(|p| pred(p)).collect(),
                               f.into_iter().map(|p| pred(p)).collect())
     }
 
-    pub fn split(self) -> (Vec<T>, Vec<T>, Vec<T>) {
-        // FIXME (#15418): this does two traversals when in principle
-        // one would suffice.  i.e. change to use `move_iter`.
-        let VecPerParamSpace { type_limit, self_limit, content } = self;
-        let mut i = 0;
-        let (prefix, fn_vec) = content.partition(|_| {
-            let on_left = i < self_limit;
-            i += 1;
-            on_left
-        });
+    pub fn split(self) -> SeparateVecsPerParamSpace<T> {
+        let VecPerParamSpace { type_limit, self_limit, assoc_limit, content } = self;
 
-        let mut i = 0;
-        let (type_vec, self_vec) = prefix.partition(|_| {
-            let on_left = i < type_limit;
-            i += 1;
-            on_left
-        });
+        let mut content_iter = content.into_iter();
 
-        (type_vec, self_vec, fn_vec)
+        SeparateVecsPerParamSpace {
+            types: content_iter.by_ref().take(type_limit).collect(),
+            selfs: content_iter.by_ref().take(self_limit - type_limit).collect(),
+            assocs: content_iter.by_ref().take(assoc_limit - self_limit).collect(),
+            fns: content_iter.collect()
+        }
     }
 
     pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
@@ -560,12 +588,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
                     this.tcx().sess.span_bug(
                         span,
                         format!("Type parameter `{}` ({}/{}/{}) out of range \
-                                 when substituting (root type={})",
+                                 when substituting (root type={}) substs={}",
                                 p.repr(this.tcx()),
                                 source_ty.repr(this.tcx()),
                                 space,
                                 index,
-                                this.root_ty.repr(this.tcx())).as_slice());
+                                this.root_ty.repr(this.tcx()),
+                                this.substs.repr(this.tcx())).as_slice());
                 }
             }
         }
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 9d0df263849..9a2d5b4d4dc 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -1618,7 +1618,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             Ok(o) => o,
             Err(ErrorReported) => Vec::new()
         };
-        let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new());
+        let obligations = VecPerParamSpace::new(obligations, Vec::new(),
+                                                Vec::new(), Vec::new());
         VtableBuiltinData { nested: obligations }
     }
 
@@ -1693,6 +1694,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 vec![arguments_tuple.subst(self.tcx(), substs),
                      new_signature.output.unwrap().subst(self.tcx(), substs)],
                 vec![],
+                vec![],
                 obligation.self_ty())
         });
 
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index db433167298..fbd4db959ce 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -205,7 +205,12 @@ pub fn trans_static_method_callee(bcx: Block,
     // type parameters that belong to the trait but also some that
     // belong to the method:
     let rcvr_substs = node_id_substs(bcx, ExprId(expr_id));
-    let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.split();
+    let subst::SeparateVecsPerParamSpace {
+        types: rcvr_type,
+        selfs: rcvr_self,
+        assocs: rcvr_assoc,
+        fns: rcvr_method
+    } = rcvr_substs.types.split();
 
     // Lookup the precise impl being called. To do that, we need to
     // create a trait reference identifying the self type and other
@@ -232,6 +237,7 @@ pub fn trans_static_method_callee(bcx: Block,
     let trait_substs =
         Substs::erased(VecPerParamSpace::new(rcvr_type,
                                              rcvr_self,
+                                             rcvr_assoc,
                                              Vec::new()));
     debug!("trait_substs={}", trait_substs.repr(bcx.tcx()));
     let trait_ref = Rc::new(ty::TraitRef { def_id: trait_id,
@@ -265,10 +271,16 @@ pub fn trans_static_method_callee(bcx: Block,
             // that with the `rcvr_method` from before, which tells us
             // the type parameters from the *method*, to yield
             // `callee_substs=[[T=int],[],[U=String]]`.
-            let (impl_type, impl_self, _) = impl_substs.types.split();
+            let subst::SeparateVecsPerParamSpace {
+                types: impl_type,
+                selfs: impl_self,
+                assocs: impl_assoc,
+                fns: _
+            } = impl_substs.types.split();
             let callee_substs =
                 Substs::erased(VecPerParamSpace::new(impl_type,
                                                      impl_self,
+                                                     impl_assoc,
                                                      rcvr_method));
 
             let mth_id = method_with_name(ccx, impl_did, mname);
@@ -397,12 +409,17 @@ fn combine_impl_and_methods_tps(bcx: Block,
 
     // Break apart the type parameters from the node and type
     // parameters from the receiver.
-    let (_, _, node_method) = node_substs.types.split();
-    let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.clone().split();
+    let node_method = node_substs.types.split().fns;
+    let subst::SeparateVecsPerParamSpace {
+        types: rcvr_type,
+        selfs: rcvr_self,
+        assocs: rcvr_assoc,
+        fns: rcvr_method
+    } = rcvr_substs.types.clone().split();
     assert!(rcvr_method.is_empty());
     subst::Substs {
         regions: subst::ErasedRegions,
-        types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method)
+        types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, rcvr_assoc, node_method)
     }
 }
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 4c088e42243..a94b188cb28 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -573,10 +573,6 @@ pub struct ctxt<'tcx> {
     /// Maps def IDs to true if and only if they're associated types.
     pub associated_types: RefCell<DefIdMap<bool>>,
 
-    /// Maps def IDs of traits to information about their associated types.
-    pub trait_associated_types:
-        RefCell<DefIdMap<Rc<Vec<AssociatedTypeInfo>>>>,
-
     /// Caches the results of trait selection. This cache is used
     /// for things that do not have to do with the parameters in scope.
     pub selection_cache: traits::SelectionCache,
@@ -1564,7 +1560,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
         stability: RefCell::new(stability),
         capture_modes: capture_modes,
         associated_types: RefCell::new(DefIdMap::new()),
-        trait_associated_types: RefCell::new(DefIdMap::new()),
         selection_cache: traits::SelectionCache::new(),
         repr_hint_cache: RefCell::new(DefIdMap::new()),
    }
@@ -1994,6 +1989,16 @@ impl ItemSubsts {
     }
 }
 
+impl ParamBounds {
+    pub fn empty() -> ParamBounds {
+        ParamBounds {
+            builtin_bounds: empty_builtin_bounds(),
+            trait_bounds: Vec::new(),
+            region_bounds: Vec::new(),
+        }
+    }
+}
+
 // Type utilities
 
 pub fn type_is_nil(ty: t) -> bool {
@@ -4155,18 +4160,6 @@ impl Ord for AssociatedTypeInfo {
     }
 }
 
-/// Returns the associated types belonging to the given trait, in parameter
-/// order.
-pub fn associated_types_for_trait(cx: &ctxt, trait_id: ast::DefId)
-                                  -> Rc<Vec<AssociatedTypeInfo>> {
-    cx.trait_associated_types
-      .borrow()
-      .find(&trait_id)
-      .expect("associated_types_for_trait(): trait not found, try calling \
-               ensure_associated_types()")
-      .clone()
-}
-
 pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId)
                           -> Rc<Vec<ImplOrTraitItemId>> {
     lookup_locally_or_in_crate_store("trait_item_def_ids",
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index fb0406d83c6..7c8d9309df3 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -54,7 +54,7 @@ use middle::def;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem};
 use middle::lang_items::{FnOnceTraitLangItem};
 use middle::resolve_lifetime as rl;
-use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
+use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs};
 use middle::subst::{VecPerParamSpace};
 use middle::ty;
 use middle::typeck::lookup_def_tcx;
@@ -215,7 +215,8 @@ fn ast_path_substs<'tcx,AC,RS>(
                    associated_ty: Option<ty::t>,
                    path: &ast::Path)
                    -> Substs
-                   where AC: AstConv<'tcx>, RS: RegionScope {
+                   where AC: AstConv<'tcx>, RS: RegionScope
+{
     /*!
      * Given a path `path` that refers to an item `I` with the
      * declared generics `decl_generics`, returns an appropriate
@@ -338,17 +339,21 @@ fn ast_path_substs<'tcx,AC,RS>(
                 substs.types.push(TypeSpace, default);
             }
             None => {
-                // This is an associated type.
-                substs.types.push(
-                    TypeSpace,
-                    this.associated_type_binding(path.span,
-                                                 associated_ty,
-                                                 decl_def_id,
-                                                 param.def_id))
+                tcx.sess.span_bug(path.span,
+                                  "extra parameter without default");
             }
         }
     }
 
+    for param in decl_generics.types.get_slice(AssocSpace).iter() {
+        substs.types.push(
+            AssocSpace,
+            this.associated_type_binding(path.span,
+                                         associated_ty,
+                                         decl_def_id,
+                                         param.def_id))
+    }
+
     substs
 }
 
@@ -628,9 +633,13 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
         a_seq_ty: &ast::Ty,
         ptr_ty: PointerTy,
         constr: |ty::t| -> ty::t)
-        -> ty::t {
+        -> ty::t
+{
     let tcx = this.tcx();
-    debug!("mk_pointer(ptr_ty={})", ptr_ty);
+
+    debug!("mk_pointer(ptr_ty={}, a_seq_ty={})",
+           ptr_ty,
+           a_seq_ty.repr(tcx));
 
     match a_seq_ty.node {
         ast::TyVec(ref ty) => {
@@ -730,7 +739,13 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC,
                                    trait_type_id: ast::DefId,
                                    span: Span)
                                    -> ty::t
-                                   where AC: AstConv<'tcx>, RS: RegionScope {
+                                   where AC: AstConv<'tcx>, RS: RegionScope
+{
+    debug!("associated_ty_to_ty(trait_path={}, for_ast_type={}, trait_type_id={})",
+           trait_path.repr(this.tcx()),
+           for_ast_type.repr(this.tcx()),
+           trait_type_id.repr(this.tcx()));
+
     // Find the trait that this associated type belongs to.
     let trait_did = match ty::impl_or_trait_item(this.tcx(),
                                                  trait_type_id).container() {
@@ -757,9 +772,16 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC,
                                           None,
                                           Some(for_type),
                                           trait_path);
+
+    debug!("associated_ty_to_ty(trait_ref={})",
+           trait_ref.repr(this.tcx()));
+
     let trait_def = this.get_trait_def(trait_did);
     for type_parameter in trait_def.generics.types.iter() {
         if type_parameter.def_id == trait_type_id {
+            debug!("associated_ty_to_ty(type_parameter={} substs={})",
+                   type_parameter.repr(this.tcx()),
+                   trait_ref.substs.repr(this.tcx()));
             return *trait_ref.substs.types.get(type_parameter.space,
                                                type_parameter.index)
         }
@@ -772,7 +794,10 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC,
 // Parses the programmer's textual representation of a type into our
 // internal notion of a type.
 pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
-        this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t {
+        this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t
+{
+    debug!("ast_ty_to_ty(ast_ty={})",
+           ast_ty.repr(this.tcx()));
 
     let tcx = this.tcx();
 
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 847d8e88bde..863f09736ab 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -298,13 +298,19 @@ fn collect_trait_methods(ccx: &CrateCtxt,
                                             &*m.pe_fn_decl())
                                     }
                                     ast::TypeTraitItem(ref at) => {
-                                        tcx.sess.span_bug(at.span,
+                                        tcx.sess.span_bug(at.ty_param.span,
                                                           "there shouldn't \
                                                            be a type trait \
                                                            item here")
                                     }
                                 });
 
+                                debug!("ty_method_of_trait_method yielded {} \
+                                        for method {} of trait {}",
+                                       ty_method.repr(ccx.tcx),
+                                       trait_item.repr(ccx.tcx),
+                                       local_def(trait_id).repr(ccx.tcx));
+
                                 make_method_ty(ccx, &*ty_method);
 
                                 tcx.impl_or_trait_items
@@ -315,9 +321,9 @@ fn collect_trait_methods(ccx: &CrateCtxt,
                             ast::TypeTraitItem(ref ast_associated_type) => {
                                 let trait_did = local_def(trait_id);
                                 let associated_type = ty::AssociatedType {
-                                    name: ast_associated_type.ident.name,
+                                    name: ast_associated_type.ty_param.ident.name,
                                     vis: ast::Public,
-                                    def_id: local_def(ast_associated_type.id),
+                                    def_id: local_def(ast_associated_type.ty_param.id),
                                     container: TraitContainer(trait_did),
                                 };
 
@@ -345,7 +351,7 @@ fn collect_trait_methods(ccx: &CrateCtxt,
                                             method.id))
                                 }
                                 ast::TypeTraitItem(ref typedef) => {
-                                    ty::TypeTraitItemId(local_def(typedef.id))
+                                    ty::TypeTraitItemId(local_def(typedef.ty_param.id))
                                 }
                             }
                         }).collect());
@@ -460,35 +466,35 @@ fn convert_associated_type(ccx: &CrateCtxt,
     // associated type.
     let type_parameter_def = trait_def.generics
                                       .types
-                                      .get_slice(subst::TypeSpace)
+                                      .get_slice(subst::AssocSpace)
                                       .iter()
                                       .find(|def| {
-        def.def_id == local_def(associated_type.id)
+        def.def_id == local_def(associated_type.ty_param.id)
     });
     let type_parameter_def = match type_parameter_def {
         Some(type_parameter_def) => type_parameter_def,
         None => {
-            ccx.tcx().sess.span_bug(associated_type.span,
+            ccx.tcx().sess.span_bug(associated_type.ty_param.span,
                                     "`convert_associated_type()` didn't find \
                                      a type parameter ID corresponding to \
                                      this type")
         }
     };
     let param_type = ty::mk_param(ccx.tcx,
-                                  subst::TypeSpace,
+                                  type_parameter_def.space,
                                   type_parameter_def.index,
-                                  local_def(associated_type.id));
-    ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.id),
+                                  local_def(associated_type.ty_param.id));
+    ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.ty_param.id),
                                        Polytype {
                                         generics: ty::Generics::empty(),
                                         ty: param_type,
                                        });
-    write_ty_to_tcx(ccx.tcx, associated_type.id, param_type);
+    write_ty_to_tcx(ccx.tcx, associated_type.ty_param.id, param_type);
 
     let associated_type = Rc::new(ty::AssociatedType {
-        name: associated_type.ident.name,
+        name: associated_type.ty_param.ident.name,
         vis: ast::Public,
-        def_id: local_def(associated_type.id),
+        def_id: local_def(associated_type.ty_param.id),
         container: TraitContainer(trait_def.trait_ref.def_id),
     });
     ccx.tcx
@@ -780,25 +786,18 @@ impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> {
                                ty: Option<ty::t>,
                                trait_id: ast::DefId,
                                associated_type_id: ast::DefId)
-                               -> ty::t {
-        ensure_associated_types(self, trait_id);
-        let associated_type_ids = ty::associated_types_for_trait(self.ccx.tcx,
-                                                                 trait_id);
+                               -> ty::t
+    {
+        let trait_def = ty::lookup_trait_def(self.tcx(), trait_id);
         match self.opt_trait_ref_id {
             Some(trait_ref_id) if trait_ref_id == trait_id => {
                 // It's an associated type on the trait that we're
                 // implementing.
-                let associated_type_id =
-                    associated_type_ids.iter()
-                                       .find(|id| {
-                                           id.def_id == associated_type_id
-                                       })
-                                       .expect("associated_type_binding(): \
-                                                expected associated type ID \
-                                                in trait");
-                let associated_type =
-                    ty::impl_or_trait_item(self.ccx.tcx,
-                                           associated_type_id.def_id);
+                assert!(trait_def.generics.types
+                        .get_slice(subst::AssocSpace)
+                        .iter()
+                        .any(|type_param_def| type_param_def.def_id == associated_type_id));
+                let associated_type = ty::impl_or_trait_item(self.ccx.tcx, associated_type_id);
                 for impl_item in self.impl_items.iter() {
                     match *impl_item {
                         ast::MethodImplItem(_) => {}
@@ -978,9 +977,9 @@ impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> {
                 match *item {
                     ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {}
                     ast::TypeTraitItem(ref item) => {
-                        if local_def(item.id) == associated_type_id {
+                        if local_def(item.ty_param.id) == associated_type_id {
                             return ty::mk_param(self.tcx(),
-                                                subst::TypeSpace,
+                                                subst::AssocSpace,
                                                 index,
                                                 associated_type_id)
                         }
@@ -1451,7 +1450,8 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
                        trait_id: ast::NodeId,
                        generics: &ast::Generics,
                        items: &[ast::TraitItem])
-                        -> subst::Substs {
+                        -> subst::Substs
+    {
         // Creates a no-op substitution for the trait's type parameters.
         let regions =
             generics.lifetimes
@@ -1464,7 +1464,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
                     .collect();
 
         // Start with the generics in the type parameters...
-        let mut types: Vec<_> =
+        let types: Vec<_> =
             generics.ty_params
                     .iter()
                     .enumerate()
@@ -1472,24 +1472,27 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
                                                  i, local_def(def.id)))
                     .collect();
 
-        // ...and add generics synthesized from the associated types.
-        for item in items.iter() {
-            match *item {
+        // ...and also create generics synthesized from the associated types.
+        let assoc_types: Vec<_> =
+            items.iter()
+            .flat_map(|item| match *item {
                 ast::TypeTraitItem(ref trait_item) => {
                     let index = types.len();
-                    types.push(ty::mk_param(ccx.tcx,
-                                            subst::TypeSpace,
-                                            index,
-                                            local_def(trait_item.id)))
+                    Some(ty::mk_param(ccx.tcx,
+                                      subst::AssocSpace,
+                                      index,
+                                      local_def(trait_item.ty_param.id))).into_iter()
                 }
-                ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {}
-            }
-        }
+                ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {
+                    None.into_iter()
+                }
+            })
+            .collect();
 
         let self_ty =
             ty::mk_param(ccx.tcx, subst::SelfSpace, 0, local_def(trait_id));
 
-        subst::Substs::new_trait(types, regions, self_ty)
+        subst::Substs::new_trait(types, regions, assoc_types, self_ty)
     }
 }
 
@@ -1630,11 +1633,11 @@ fn ty_of_trait_item(ccx: &CrateCtxt, trait_item: &ast::TraitItem)
                                   "ty_of_trait_item() on provided method")
         }
         ast::TypeTraitItem(ref associated_type) => {
-            let parent = ccx.tcx.map.get_parent(associated_type.id);
+            let parent = ccx.tcx.map.get_parent(associated_type.ty_param.id);
             let trait_def = match ccx.tcx.map.get(parent) {
                 ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item),
                 _ => {
-                    ccx.tcx.sess.span_bug(associated_type.span,
+                    ccx.tcx.sess.span_bug(associated_type.ty_param.span,
                                           "associated type's parent wasn't \
                                            an item?!")
                 }
@@ -1661,38 +1664,33 @@ fn ty_generics_for_type(ccx: &CrateCtxt,
 fn ty_generics_for_trait(ccx: &CrateCtxt,
                          trait_id: ast::NodeId,
                          substs: &subst::Substs,
-                         generics: &ast::Generics,
+                         ast_generics: &ast::Generics,
                          items: &[ast::TraitItem])
                          -> ty::Generics {
     let mut generics =
         ty_generics(ccx,
                     subst::TypeSpace,
-                    generics.lifetimes.as_slice(),
-                    generics.ty_params.as_slice(),
+                    ast_generics.lifetimes.as_slice(),
+                    ast_generics.ty_params.as_slice(),
                     ty::Generics::empty(),
-                    &generics.where_clause,
+                    &ast_generics.where_clause,
                     DontCreateTypeParametersForAssociatedTypes);
 
     // Add in type parameters for any associated types.
     for item in items.iter() {
         match *item {
             ast::TypeTraitItem(ref associated_type) => {
-                let def = ty::TypeParameterDef {
-                    space: subst::TypeSpace,
-                    index: generics.types.len(subst::TypeSpace),
-                    name: associated_type.ident.name,
-                    def_id: local_def(associated_type.id),
-                    bounds: ty::ParamBounds {
-                        builtin_bounds: ty::empty_builtin_bounds(),
-                        trait_bounds: Vec::new(),
-                        region_bounds: Vec::new(),
-                    },
-                    associated_with: Some(local_def(trait_id)),
-                    default: None,
-                };
-                ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.id,
+                let def =
+                    get_or_create_type_parameter_def(
+                        ccx,
+                        subst::AssocSpace,
+                        &associated_type.ty_param,
+                        generics.types.len(subst::TypeSpace),
+                        &ast_generics.where_clause,
+                        Some(local_def(trait_id)));
+                ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id,
                                                           def.clone());
-                generics.types.push(subst::TypeSpace, def);
+                generics.types.push(subst::AssocSpace, def);
             }
             ast::ProvidedMethod(_) | ast::RequiredMethod(_) => {}
         }
@@ -1791,86 +1789,17 @@ enum CreateTypeParametersForAssociatedTypesFlag {
     CreateTypeParametersForAssociatedTypes,
 }
 
-fn ensure_associated_types<'tcx,AC>(this: &AC, trait_id: ast::DefId)
-                                    where AC: AstConv<'tcx> {
-    if this.tcx().trait_associated_types.borrow().contains_key(&trait_id) {
-        return
-    }
-
-    if trait_id.krate == ast::LOCAL_CRATE {
-        match this.tcx().map.find(trait_id.node) {
-            Some(ast_map::NodeItem(item)) => {
-                match item.node {
-                    ast::ItemTrait(_, _, _, ref trait_items) => {
-                        let mut result = Vec::new();
-                        let mut index = 0;
-                        for trait_item in trait_items.iter() {
-                            match *trait_item {
-                                ast::RequiredMethod(_) |
-                                ast::ProvidedMethod(_) => {}
-                                ast::TypeTraitItem(ref associated_type) => {
-                                    let info = ty::AssociatedTypeInfo {
-                                        def_id: local_def(associated_type.id),
-                                        index: index,
-                                        name: associated_type.ident.name,
-                                    };
-                                    result.push(info);
-                                    index += 1;
-                                }
-                            }
-                        }
-                        this.tcx()
-                            .trait_associated_types
-                            .borrow_mut()
-                            .insert(trait_id, Rc::new(result));
-                        return
-                    }
-                    _ => {
-                        this.tcx().sess.bug("ensure_associated_types() \
-                                             called on non-trait")
-                    }
-                }
-            }
-            _ => {
-                this.tcx().sess.bug("ensure_associated_types() called on \
-                                     non-trait")
-            }
-        }
-
-    }
-
-    // Cross-crate case.
-    let mut result = Vec::new();
-    let mut index = 0;
-    let trait_items = ty::trait_items(this.tcx(), trait_id);
-    for trait_item in trait_items.iter() {
-        match *trait_item {
-            ty::MethodTraitItem(_) => {}
-            ty::TypeTraitItem(ref associated_type) => {
-                let info = ty::AssociatedTypeInfo {
-                    def_id: associated_type.def_id,
-                    index: index,
-                    name: associated_type.name
-                };
-                result.push(info);
-                index += 1;
-            }
-        }
-    }
-    this.tcx().trait_associated_types.borrow_mut().insert(trait_id,
-                                                          Rc::new(result));
-}
-
 fn ty_generics<'tcx,AC>(this: &AC,
                         space: subst::ParamSpace,
                         lifetime_defs: &[ast::LifetimeDef],
                         types: &[ast::TyParam],
                         base_generics: ty::Generics,
                         where_clause: &ast::WhereClause,
-                        create_type_parameters_for_associated_types:
+                        create_type_parameters_for_associated_types_flag:
                         CreateTypeParametersForAssociatedTypesFlag)
                         -> ty::Generics
-                        where AC: AstConv<'tcx> {
+                        where AC: AstConv<'tcx>
+{
     let mut result = base_generics;
 
     for (i, l) in lifetime_defs.iter().enumerate() {
@@ -1891,62 +1820,11 @@ fn ty_generics<'tcx,AC>(this: &AC,
     // First, create the virtual type parameters for associated types if
     // necessary.
     let mut associated_types_generics = ty::Generics::empty();
-    match create_type_parameters_for_associated_types {
+    match create_type_parameters_for_associated_types_flag {
         DontCreateTypeParametersForAssociatedTypes => {}
         CreateTypeParametersForAssociatedTypes => {
-            let mut index = 0;
-            for param in types.iter() {
-                for bound in param.bounds.iter() {
-                    match *bound {
-                        ast::TraitTyParamBound(ref trait_bound) => {
-                            match lookup_def_tcx(this.tcx(),
-                                                 trait_bound.path.span,
-                                                 trait_bound.ref_id) {
-                                def::DefTrait(trait_did) => {
-                                    ensure_associated_types(this, trait_did);
-                                    let associated_types =
-                                        ty::associated_types_for_trait(
-                                            this.tcx(),
-                                            trait_did);
-                                    for associated_type_info in
-                                            associated_types.iter() {
-                                        let associated_type_trait_item =
-                                            ty::impl_or_trait_item(
-                                                this.tcx(),
-                                                associated_type_info.def_id);
-                                        let def = ty::TypeParameterDef {
-                                            name: associated_type_trait_item.name(),
-                                            def_id: associated_type_info.def_id,
-                                            space: space,
-                                            index: types.len() + index,
-                                            bounds: ty::ParamBounds {
-                                                builtin_bounds:
-                                                ty::empty_builtin_bounds(),
-                                                trait_bounds: Vec::new(),
-                                                region_bounds: Vec::new(),
-                                            },
-                                            associated_with: {
-                                                Some(local_def(param.id))
-                                            },
-                                            default: None,
-                                        };
-                                        associated_types_generics.types
-                                                                 .push(space,
-                                                                       def);
-                                        index += 1;
-                                    }
-                                }
-                                _ => {
-                                    this.tcx().sess.span_bug(trait_bound.path
-                                                                        .span,
-                                                             "not a trait?!")
-                                }
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-            }
+            create_type_parameters_for_associated_types(this, space, types,
+                                                        &mut associated_types_generics);
         }
     }
 
@@ -1960,7 +1838,8 @@ fn ty_generics<'tcx,AC>(this: &AC,
                                                    space,
                                                    param,
                                                    i,
-                                                   where_clause);
+                                                   where_clause,
+                                                   None);
         debug!("ty_generics: def for type param: {}, {}",
                def.repr(this.tcx()),
                space);
@@ -1981,62 +1860,140 @@ fn ty_generics<'tcx,AC>(this: &AC,
 
     return result;
 
-    fn get_or_create_type_parameter_def<'tcx,AC>(
-                                        this: &AC,
-                                        space: subst::ParamSpace,
-                                        param: &ast::TyParam,
-                                        index: uint,
-                                        where_clause: &ast::WhereClause)
-                                        -> ty::TypeParameterDef
-                                        where AC: AstConv<'tcx> {
-        match this.tcx().ty_param_defs.borrow().find(&param.id) {
-            Some(d) => { return (*d).clone(); }
-            None => { }
+    fn create_type_parameters_for_associated_types<'tcx,AC>(
+        this: &AC,
+        space: subst::ParamSpace,
+        types: &[ast::TyParam],
+        associated_types_generics: &mut ty::Generics)
+        where AC: AstConv<'tcx>
+    {
+        // The idea here is roughly as follows. We start with
+        // an item that is paramerized by various type parameters
+        // with bounds:
+        //
+        //    fn foo<T:Iterator>(t: T) { ... }
+        //
+        // The traits in those bounds declare associated types:
+        //
+        //    trait Iterator { type Elem; ... }
+        //
+        // And we rewrite the original function so that every associated
+        // type is bound to some fresh type parameter:
+        //
+        //    fn foo<A,T:Iterator<Elem=A>>(t: T) { ... }
+
+        // Number of synthetic type parameters created thus far
+        let mut index = 0;
+
+        // Iterate over the each type parameter `T` (from the example)
+        for param in types.iter() {
+            // Iterate over the bound `Iterator`
+            for bound in param.bounds.iter() {
+                // In the above example, `ast_trait_ref` is `Iterator`.
+                let ast_trait_ref = match *bound {
+                    ast::TraitTyParamBound(ref r) => r,
+                    ast::UnboxedFnTyParamBound(..) => { continue; }
+                    ast::RegionTyParamBound(..) => { continue; }
+                };
+
+                let trait_def_id =
+                    match lookup_def_tcx(this.tcx(),
+                                         ast_trait_ref.path.span,
+                                         ast_trait_ref.ref_id) {
+                        def::DefTrait(trait_def_id) => trait_def_id,
+                        _ => {
+                            this.tcx().sess.span_bug(ast_trait_ref.path.span,
+                                                     "not a trait?!")
+                        }
+                    };
+
+                // trait_def_id is def-id of `Iterator`
+                let trait_def = ty::lookup_trait_def(this.tcx(), trait_def_id);
+                let associated_type_defs = trait_def.generics.types.get_slice(subst::AssocSpace);
+
+                // Iterate over each associated type `Elem`
+                for associated_type_def in associated_type_defs.iter() {
+                    // Create the fresh type parameter `A`
+                    let def = ty::TypeParameterDef {
+                        name: associated_type_def.name,
+                        def_id: associated_type_def.def_id,
+                        space: space,
+                        index: types.len() + index,
+                        bounds: ty::ParamBounds {
+                            builtin_bounds: associated_type_def.bounds.builtin_bounds,
+
+                            // FIXME(#18178) -- we should add the other bounds, but
+                            // that requires subst and more logic
+                            trait_bounds: Vec::new(),
+                            region_bounds: Vec::new(),
+                        },
+                        associated_with: Some(local_def(param.id)),
+                        default: None,
+                    };
+                    associated_types_generics.types.push(space, def);
+                    index += 1;
+                }
+            }
         }
+    }
+}
 
-        let param_ty = ty::ParamTy::new(space, index, local_def(param.id));
-        let bounds = compute_bounds(this,
-                                    param.ident.name,
-                                    param_ty,
-                                    param.bounds.as_slice(),
-                                    &param.unbound,
-                                    param.span,
-                                    where_clause);
-        let default = match param.default {
-            None => None,
-            Some(ref path) => {
-                let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path);
-                let cur_idx = index;
-
-                ty::walk_ty(ty, |t| {
-                    match ty::get(t).sty {
-                        ty::ty_param(p) => if p.idx > cur_idx {
+fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC,
+                                             space: subst::ParamSpace,
+                                             param: &ast::TyParam,
+                                             index: uint,
+                                             where_clause: &ast::WhereClause,
+                                             associated_with: Option<ast::DefId>)
+                                             -> ty::TypeParameterDef
+    where AC: AstConv<'tcx>
+{
+    match this.tcx().ty_param_defs.borrow().find(&param.id) {
+        Some(d) => { return (*d).clone(); }
+        None => { }
+    }
+
+    let param_ty = ty::ParamTy::new(space, index, local_def(param.id));
+    let bounds = compute_bounds(this,
+                                param.ident.name,
+                                param_ty,
+                                param.bounds.as_slice(),
+                                &param.unbound,
+                                param.span,
+                                where_clause);
+    let default = match param.default {
+        None => None,
+        Some(ref path) => {
+            let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path);
+            let cur_idx = index;
+
+            ty::walk_ty(ty, |t| {
+                match ty::get(t).sty {
+                    ty::ty_param(p) => if p.idx > cur_idx {
                         span_err!(this.tcx().sess, path.span, E0128,
                                   "type parameters with a default cannot use \
                                    forward declared identifiers");
                         },
                         _ => {}
                     }
-                });
+            });
 
-                Some(ty)
-            }
-        };
+            Some(ty)
+        }
+    };
 
-        let def = ty::TypeParameterDef {
-            space: space,
-            index: index,
-            name: param.ident.name,
-            def_id: local_def(param.id),
-            associated_with: None,
-            bounds: bounds,
-            default: default
-        };
+    let def = ty::TypeParameterDef {
+        space: space,
+        index: index,
+        name: param.ident.name,
+        def_id: local_def(param.id),
+        associated_with: associated_with,
+        bounds: bounds,
+        default: default
+    };
 
-        this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone());
+    this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone());
 
-        def
-    }
+    def
 }
 
 fn compute_bounds<'tcx,AC>(this: &AC,
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 227a9b1bdcc..55c3c236853 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -774,10 +774,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         assert!(generics.regions.len(subst::FnSpace) == 0);
 
         let type_parameter_count = generics.types.len(subst::TypeSpace);
+        let type_parameters = self.next_ty_vars(type_parameter_count);
+
         let region_param_defs = generics.regions.get_slice(subst::TypeSpace);
         let regions = self.region_vars_for_defs(span, region_param_defs);
-        let type_parameters = self.next_ty_vars(type_parameter_count);
-        subst::Substs::new_trait(type_parameters, regions, self_ty)
+
+        let assoc_type_parameter_count = generics.types.len(subst::AssocSpace);
+        let assoc_type_parameters = self.next_ty_vars(assoc_type_parameter_count);
+
+        subst::Substs::new_trait(type_parameters, regions, assoc_type_parameters, self_ty)
     }
 
     pub fn fresh_bound_region(&self, binder_id: ast::NodeId) -> ty::Region {
@@ -791,7 +796,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
     pub fn ty_to_string(&self, t: ty::t) -> String {
         ty_to_string(self.tcx,
-                  self.resolve_type_vars_if_possible(t))
+                     self.resolve_type_vars_if_possible(t))
     }
 
     pub fn tys_to_string(&self, ts: &[ty::t]) -> String {
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index b820780dbf9..fb80b9f30f5 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -425,7 +425,13 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
         }
         ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty),
         ty_err => "[type error]".to_string(),
-        ty_param(ref param_ty) => param_ty.repr(cx),
+        ty_param(ref param_ty) => {
+            if cx.sess.verbose() {
+                param_ty.repr(cx)
+            } else {
+                param_ty.user_string(cx)
+            }
+        }
         ty_enum(did, ref substs) | ty_struct(did, ref substs) => {
             let base = ty::item_path_str(cx, did);
             let generics = ty::lookup_item_type(cx, did).generics;
@@ -481,6 +487,17 @@ pub fn parameterized(cx: &ctxt,
                      generics: &ty::Generics)
                      -> String
 {
+    if cx.sess.verbose() {
+        if substs.is_noop() {
+            return format!("{}", base);
+        } else {
+            return format!("{}<{},{}>",
+                           base,
+                           substs.regions.repr(cx),
+                           substs.types.repr(cx));
+        }
+    }
+
     let mut strs = Vec::new();
 
     match substs.regions {
@@ -505,7 +522,7 @@ pub fn parameterized(cx: &ctxt,
     let tps = substs.types.get_slice(subst::TypeSpace);
     let ty_params = generics.types.get_slice(subst::TypeSpace);
     let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some());
-    let num_defaults = if has_defaults && !cx.sess.verbose() {
+    let num_defaults = if has_defaults {
         ty_params.iter().zip(tps.iter()).rev().take_while(|&(def, &actual)| {
             match def.default {
                 Some(default) => default.subst(cx, substs) == actual,
@@ -520,18 +537,6 @@ pub fn parameterized(cx: &ctxt,
         strs.push(ty_to_string(cx, *t))
     }
 
-    if cx.sess.verbose() {
-        for t in substs.types.get_slice(subst::SelfSpace).iter() {
-            strs.push(format!("self {}", t.repr(cx)));
-        }
-
-        // generally there shouldn't be any substs in the fn param
-        // space, but in verbose mode, print them out.
-        for t in substs.types.get_slice(subst::FnSpace).iter() {
-            strs.push(format!("fn {}", t.repr(cx)));
-        }
-    }
-
     if strs.len() > 0u {
         format!("{}<{}>", base, strs.connect(", "))
     } else {
@@ -668,10 +673,11 @@ impl Repr for subst::Substs {
 
 impl<T:Repr> Repr for subst::VecPerParamSpace<T> {
     fn repr(&self, tcx: &ctxt) -> String {
-        format!("[{};{};{}]",
-                       self.get_slice(subst::TypeSpace).repr(tcx),
-                       self.get_slice(subst::SelfSpace).repr(tcx),
-                       self.get_slice(subst::FnSpace).repr(tcx))
+        format!("[{};{};{};{}]",
+                self.get_slice(subst::TypeSpace).repr(tcx),
+                self.get_slice(subst::SelfSpace).repr(tcx),
+                self.get_slice(subst::AssocSpace).repr(tcx),
+                self.get_slice(subst::FnSpace).repr(tcx))
     }
 }
 
@@ -726,7 +732,7 @@ impl Repr for ty::TraitRef {
     fn repr(&self, tcx: &ctxt) -> String {
         let base = ty::item_path_str(tcx, self.def_id);
         let trait_def = ty::lookup_trait_def(tcx, self.def_id);
-        format!("<{} as {}>",
+        format!("<{} : {}>",
                 self.substs.self_ty().repr(tcx),
                 parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics))
     }
@@ -741,6 +747,19 @@ impl Repr for ty::TraitDef {
     }
 }
 
+impl Repr for ast::TraitItem {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        match *self {
+            ast::RequiredMethod(ref data) => format!("RequiredMethod({}, id={})",
+                                                     data.ident, data.id),
+            ast::ProvidedMethod(ref data) => format!("ProvidedMethod(id={})",
+                                                     data.id),
+            ast::TypeTraitItem(ref data) => format!("TypeTraitItem({}, id={})",
+                                                     data.ty_param.ident, data.ty_param.id),
+        }
+    }
+}
+
 impl Repr for ast::Expr {
     fn repr(&self, _tcx: &ctxt) -> String {
         format!("expr({}: {})", self.id, pprust::expr_to_string(self))
@@ -759,6 +778,12 @@ impl UserString for ast::Path {
     }
 }
 
+impl Repr for ast::Ty {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("type({})", pprust::ty_to_string(self))
+    }
+}
+
 impl Repr for ast::Item {
     fn repr(&self, tcx: &ctxt) -> String {
         format!("item({})", tcx.map.node_to_string(self.id))
@@ -1262,7 +1287,8 @@ impl UserString for ParamTy {
 
 impl Repr for ParamTy {
     fn repr(&self, tcx: &ctxt) -> String {
-        self.user_string(tcx)
+        let ident = self.user_string(tcx);
+        format!("{}/{}.{}", ident, self.space, self.idx)
     }
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c128588918e..f96b3916f06 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2203,12 +2203,12 @@ impl Clean<Stability> for attr::Stability {
 impl Clean<Item> for ast::AssociatedType {
     fn clean(&self, cx: &DocContext) -> Item {
         Item {
-            source: self.span.clean(cx),
-            name: Some(self.ident.clean(cx)),
+            source: self.ty_param.span.clean(cx),
+            name: Some(self.ty_param.ident.clean(cx)),
             attrs: self.attrs.clean(cx),
             inner: AssociatedTypeItem,
             visibility: None,
-            def_id: ast_util::local_def(self.id),
+            def_id: ast_util::local_def(self.ty_param.id),
             stability: None,
         }
     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 1edcb35289a..7fb93698219 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -861,10 +861,8 @@ pub enum ImplItem {
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub struct AssociatedType {
-    pub id: NodeId,
-    pub span: Span,
-    pub ident: Ident,
     pub attrs: Vec<Attribute>,
+    pub ty_param: TyParam,
 }
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index fa36577ebdb..f049b964ff3 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -405,7 +405,9 @@ impl<'ast> Map<'ast> {
                         MethMac(_) => panic!("no path elem for {}", node),
                     }
                 }
-                TypeTraitItem(ref m) => PathName(m.ident.name),
+                TypeTraitItem(ref m) => {
+                    PathName(m.ty_param.ident.name)
+                }
             },
             NodeVariant(v) => PathName(v.node.name.name),
             _ => panic!("no path elem for {}", node)
@@ -510,7 +512,7 @@ impl<'ast> Map<'ast> {
                 match *trait_method {
                     RequiredMethod(ref type_method) => type_method.span,
                     ProvidedMethod(ref method) => method.span,
-                    TypeTraitItem(ref typedef) => typedef.span,
+                    TypeTraitItem(ref typedef) => typedef.ty_param.span,
                 }
             }
             Some(NodeImplItem(ref impl_item)) => {
@@ -650,7 +652,7 @@ impl Named for TraitItem {
         match *self {
             RequiredMethod(ref tm) => tm.ident.name,
             ProvidedMethod(ref m) => m.name(),
-            TypeTraitItem(ref at) => at.ident.name,
+            TypeTraitItem(ref at) => at.ty_param.ident.name,
         }
     }
 }
@@ -783,7 +785,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
                             self.insert(m.id, NodeTraitItem(tm));
                         }
                         TypeTraitItem(ref typ) => {
-                            self.insert(typ.id, NodeTraitItem(tm));
+                            self.insert(typ.ty_param.id, NodeTraitItem(tm));
                         }
                     }
                 }
@@ -976,7 +978,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
             let trait_item_id = match *trait_item {
                 ProvidedMethod(ref m) => m.id,
                 RequiredMethod(ref m) => m.id,
-                TypeTraitItem(ref ty) => ty.id,
+                TypeTraitItem(ref ty) => ty.ty_param.id,
             };
 
             collector.insert(trait_item_id, NodeTraitItem(trait_item));
@@ -1080,7 +1082,7 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String {
                 }
                 TypeTraitItem(ref t) => {
                     format!("type item {} in {} (id={})",
-                            token::get_ident(t.ident),
+                            token::get_ident(t.ty_param.ident),
                             map.path_to_string(id),
                             id)
                 }
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 863f53be798..3aa60236d70 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -524,7 +524,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),
+            ast::TypeTraitItem(ref typ) => self.operation.visit_id(typ.ty_param.id),
         }
         visit::walk_trait_item(self, tm);
     }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 330e4552e2f..7701f495f72 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -260,7 +260,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
             ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {}
             ast::TypeTraitItem(ref ti) => {
                 self.gate_feature("associated_types",
-                                  ti.span,
+                                  ti.ty_param.span,
                                   "associated types are experimental")
             }
         }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 9a55f07e98d..6535c8e89fd 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -793,19 +793,16 @@ pub fn noop_fold_typedef<T>(t: Typedef, folder: &mut T)
 
 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);
+                                    where T: Folder
+{
     let new_attrs = at.attrs
                       .iter()
                       .map(|attr| folder.fold_attribute((*attr).clone()))
                       .collect();
+    let new_param = folder.fold_ty_param(at.ty_param);
     ast::AssociatedType {
-        ident: new_ident,
         attrs: new_attrs,
-        id: new_id,
-        span: new_span,
+        ty_param: new_param,
     }
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 5e18c6bae48..37b9a0793b4 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1229,16 +1229,13 @@ impl<'a> Parser<'a> {
     /// 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;
+                             -> AssociatedType
+    {
+        let ty_param = self.parse_ty_param();
         self.expect(&token::Semi);
         AssociatedType {
-            id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, hi),
-            ident: ident,
             attrs: attrs,
+            ty_param: ty_param,
         }
     }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 4cfc95d4c3f..4cae3691f2a 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -815,9 +815,11 @@ impl<'a> State<'a> {
     }
 
     fn print_associated_type(&mut self, typedef: &ast::AssociatedType)
-                             -> IoResult<()> {
+                             -> IoResult<()>
+    {
+        try!(self.print_outer_attributes(typedef.attrs[]));
         try!(self.word_space("type"));
-        try!(self.print_ident(typedef.ident));
+        try!(self.print_ty_param(&typedef.ty_param));
         word(&mut self.s, ";")
     }
 
@@ -2431,23 +2433,7 @@ impl<'a> State<'a> {
             } else {
                 let idx = idx - generics.lifetimes.len();
                 let param = generics.ty_params.get(idx);
-                match param.unbound {
-                    Some(TraitTyParamBound(ref tref)) => {
-                        try!(s.print_trait_ref(tref));
-                        try!(s.word_space("?"));
-                    }
-                    _ => {}
-                }
-                try!(s.print_ident(param.ident));
-                try!(s.print_bounds(":", &param.bounds));
-                match param.default {
-                    Some(ref default) => {
-                        try!(space(&mut s.s));
-                        try!(s.word_space("="));
-                        s.print_type(&**default)
-                    }
-                    _ => Ok(())
-                }
+                s.print_ty_param(param)
             }
         }));
 
@@ -2455,6 +2441,26 @@ impl<'a> State<'a> {
         Ok(())
     }
 
+    pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> {
+        match param.unbound {
+            Some(TraitTyParamBound(ref tref)) => {
+                try!(self.print_trait_ref(tref));
+                try!(self.word_space("?"));
+            }
+            _ => {}
+        }
+        try!(self.print_ident(param.ident));
+        try!(self.print_bounds(":", &param.bounds));
+        match param.default {
+            Some(ref default) => {
+                try!(space(&mut self.s));
+                try!(self.word_space("="));
+                self.print_type(&**default)
+            }
+            _ => Ok(())
+        }
+    }
+
     pub fn print_where_clause(&mut self, generics: &ast::Generics)
                               -> IoResult<()> {
         if generics.where_clause.predicates.len() == 0 {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index bec72e88f99..86ee23d71a6 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -596,7 +596,8 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_method: &'v Tr
         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)
+            visitor.visit_ident(associated_type.ty_param.span,
+                                associated_type.ty_param.ident)
         }
     }
 }
diff --git a/src/test/compile-fail/associated-types-unsized.rs b/src/test/compile-fail/associated-types-unsized.rs
new file mode 100644
index 00000000000..47ab09d279f
--- /dev/null
+++ b/src/test/compile-fail/associated-types-unsized.rs
@@ -0,0 +1,24 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_types)]
+
+trait Get {
+    type Sized? Value;
+    fn get(&self) -> <Self as Get>::Value;
+}
+
+fn foo<T:Get>(t: T) {
+    let x = t.get(); //~ ERROR the trait `core::kinds::Sized` is not implemented
+}
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs
index fa38482b21c..48813ff142c 100644
--- a/src/test/compile-fail/variance-regions-direct.rs
+++ b/src/test/compile-fail/variance-regions-direct.rs
@@ -14,7 +14,7 @@
 // Regions that just appear in normal spots are contravariant:
 
 #[rustc_variance]
-struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]]
+struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[];[]]
     x: &'a int,
     y: &'b [int],
     c: &'c str
@@ -23,7 +23,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]]
 // Those same annotations in function arguments become covariant:
 
 #[rustc_variance]
-struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]]
+struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[];[]]
     x: extern "Rust" fn(&'a int),
     y: extern "Rust" fn(&'b [int]),
     c: extern "Rust" fn(&'c str),
@@ -32,7 +32,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]]
 // Mutability induces invariance:
 
 #[rustc_variance]
-struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]]
+struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[];[]]
     x: &'a mut &'b int,
 }
 
@@ -40,7 +40,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]]
 // contravariant context:
 
 #[rustc_variance]
-struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]]
+struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[];[]]
     x: extern "Rust" fn(&'a mut &'b int),
 }
 
@@ -50,21 +50,21 @@ struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]]
 // argument list occurs in an invariant context.
 
 #[rustc_variance]
-struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[]]
+struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[];[]]
     x: &'a mut extern "Rust" fn(&'b int),
 }
 
 // No uses at all is bivariant:
 
 #[rustc_variance]
-struct Test7<'a> { //~ ERROR regions=[[*];[];[]]
+struct Test7<'a> { //~ ERROR regions=[[*];[];[];[]]
     x: int
 }
 
 // Try enums too.
 
 #[rustc_variance]
-enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]]
+enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[];[]]
     Test8A(extern "Rust" fn(&'a int)),
     Test8B(&'b [int]),
     Test8C(&'b mut &'c str),
diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs
index c049fbc0fed..0e8e52df456 100644
--- a/src/test/compile-fail/variance-regions-indirect.rs
+++ b/src/test/compile-fail/variance-regions-indirect.rs
@@ -13,29 +13,29 @@
 // Try enums too.
 
 #[rustc_variance]
-enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]]
+enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[];[]]
     Test8A(extern "Rust" fn(&'a int)),
     Test8B(&'b [int]),
     Test8C(&'b mut &'c str),
 }
 
 #[rustc_variance]
-struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]]
+struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[];[]]
     f: Base<'z, 'y, 'x, 'w>
 }
 
 #[rustc_variance] // Combine - and + to yield o
-struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[]]
+struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[];[]]
     f: Base<'a, 'a, 'b, 'c>
 }
 
 #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
-struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]]
+struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[];[]]
     f: Base<'a, 'b, 'a, 'c>
 }
 
 #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
-struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]]
+struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[];[]]
     f: Base<'a, 'b, 'c, 'a>
 }
 
diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs
index c61f2ff79c0..c576c5e2edd 100644
--- a/src/test/compile-fail/variance-trait-object-bound.rs
+++ b/src/test/compile-fail/variance-trait-object-bound.rs
@@ -19,7 +19,7 @@ use std::mem;
 trait T { fn foo(); }
 
 #[rustc_variance]
-struct TOption<'a> { //~ ERROR regions=[[-];[];[]]
+struct TOption<'a> { //~ ERROR regions=[[-];[];[];[]]
     v: Option<Box<T + 'a>>,
 }