about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-01-05 20:02:14 +0000
committerbors <bors@rust-lang.org>2015-01-05 20:02:14 +0000
commitf11f3e7baeba3f5acf08cc6fbfee559c00e9f96e (patch)
treec9b0bef9c9c3decbc85aa64f04eaaf28ec99f972 /src
parent03268bbf35d3ff2350d987fe7b60375839abdf2e (diff)
parent928bb2be8fee3600db086cfa94775ac9110937e2 (diff)
downloadrust-f11f3e7baeba3f5acf08cc6fbfee559c00e9f96e.tar.gz
rust-f11f3e7baeba3f5acf08cc6fbfee559c00e9f96e.zip
auto merge of #20572 : nikomatsakis/rust/assoc-supertrait-stuff, r=brson
The first few commits in the PR are just general refactoring. I was intending them for some other code I didn't get around to writing yet, but might as well land them now. 

cc @japaric

Fixes #19541
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/astconv.rs318
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/collect.rs205
-rw-r--r--src/librustc_typeck/lib.rs4
-rw-r--r--src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs47
-rw-r--r--src/test/compile-fail/associated-type-projection-from-supertrait.rs56
-rw-r--r--src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs53
-rw-r--r--src/test/run-pass/associated-type-doubleendediterator-object.rs27
-rw-r--r--src/test/run-pass/associated-types-iterator-binding.rs27
9 files changed, 504 insertions, 235 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 1d62733875e..c616f4feaff 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -53,7 +53,8 @@ use middle::def;
 use middle::resolve_lifetime as rl;
 use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
 use middle::subst::{VecPerParamSpace};
-use middle::ty::{self, RegionEscape, Ty};
+use middle::traits;
+use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
 use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
              ShiftedRscope, BindingRscope};
 use TypeAndSubsts;
@@ -70,7 +71,9 @@ use syntax::print::pprust;
 
 pub trait AstConv<'tcx> {
     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
+
     fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx>;
+
     fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>;
 
     /// Return an (optional) substitution to convert bound type parameters that
@@ -162,9 +165,9 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
     r
 }
 
-pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
-    this: &AC,
-    rscope: &RS,
+pub fn opt_ast_region_to_region<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     default_span: Span,
     opt_lifetime: &Option<ast::Lifetime>) -> ty::Region
 {
@@ -241,13 +244,12 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
 
 /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
 /// returns an appropriate set of substitutions for this particular reference to `I`.
-fn ast_path_substs_for_ty<'tcx,AC,RS>(
-    this: &AC,
-    rscope: &RS,
+fn ast_path_substs_for_ty<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     decl_generics: &ty::Generics<'tcx>,
     path: &ast::Path)
     -> Substs<'tcx>
-    where AC: AstConv<'tcx>, RS: RegionScope
 {
     let tcx = this.tcx();
 
@@ -285,16 +287,15 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>(
                                regions)
 }
 
-fn create_substs_for_ast_path<'tcx,AC,RS>(
-    this: &AC,
-    rscope: &RS,
+fn create_substs_for_ast_path<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     span: Span,
     decl_generics: &ty::Generics<'tcx>,
     self_ty: Option<Ty<'tcx>>,
     types: Vec<Ty<'tcx>>,
     regions: Vec<ty::Region>)
- -> Substs<'tcx>
-    where AC: AstConv<'tcx>, RS: RegionScope
+    -> Substs<'tcx>
 {
     let tcx = this.tcx();
 
@@ -408,13 +409,12 @@ struct ConvertedBinding<'tcx> {
     span: Span,
 }
 
-fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
-                                                    rscope: &RS,
-                                                    data: &ast::AngleBracketedParameterData)
-                                                    -> (Vec<ty::Region>,
-                                                        Vec<Ty<'tcx>>,
-                                                        Vec<ConvertedBinding<'tcx>>)
-    where AC: AstConv<'tcx>, RS: RegionScope
+fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>,
+                                            rscope: &RegionScope,
+                                            data: &ast::AngleBracketedParameterData)
+                                            -> (Vec<ty::Region>,
+                                                Vec<Ty<'tcx>>,
+                                                Vec<ConvertedBinding<'tcx>>)
 {
     let regions: Vec<_> =
         data.lifetimes.iter()
@@ -468,12 +468,11 @@ fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec<String>)
     (implied_output_region, lifetimes_for_params)
 }
 
-fn convert_ty_with_lifetime_elision<'tcx,AC>(this: &AC,
-                                             implied_output_region: Option<ty::Region>,
-                                             param_lifetimes: Vec<(String, uint)>,
-                                             ty: &ast::Ty)
-                                             -> Ty<'tcx>
-    where AC: AstConv<'tcx>
+fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
+                                          implied_output_region: Option<ty::Region>,
+                                          param_lifetimes: Vec<(String, uint)>,
+                                          ty: &ast::Ty)
+                                          -> Ty<'tcx>
 {
     match implied_output_region {
         Some(implied_output_region) => {
@@ -490,10 +489,9 @@ fn convert_ty_with_lifetime_elision<'tcx,AC>(this: &AC,
     }
 }
 
-fn convert_parenthesized_parameters<'tcx,AC>(this: &AC,
-                                             data: &ast::ParenthesizedParameterData)
-                                             -> Vec<Ty<'tcx>>
-    where AC: AstConv<'tcx>
+fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
+                                          data: &ast::ParenthesizedParameterData)
+                                          -> Vec<Ty<'tcx>>
 {
     let binding_rscope = BindingRscope::new();
     let inputs = data.inputs.iter()
@@ -517,14 +515,13 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC,
     vec![input_ty, output]
 }
 
-pub fn instantiate_poly_trait_ref<'tcx,AC,RS>(
-    this: &AC,
-    rscope: &RS,
+pub fn instantiate_poly_trait_ref<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     ast_trait_ref: &ast::PolyTraitRef,
     self_ty: Option<Ty<'tcx>>,
     poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
     -> ty::PolyTraitRef<'tcx>
-    where AC: AstConv<'tcx>, RS: RegionScope
 {
     let mut projections = Vec::new();
 
@@ -545,14 +542,13 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>(
 ///
 /// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
 /// are disallowed. Otherwise, they are pushed onto the vector given.
-pub fn instantiate_trait_ref<'tcx,AC,RS>(
-    this: &AC,
-    rscope: &RS,
+pub fn instantiate_trait_ref<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     ast_trait_ref: &ast::TraitRef,
     self_ty: Option<Ty<'tcx>>,
     projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
     -> Rc<ty::TraitRef<'tcx>>
-    where AC: AstConv<'tcx>, RS: RegionScope
 {
     match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) {
         def::DefTrait(trait_def_id) => {
@@ -573,15 +569,14 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(
     }
 }
 
-fn ast_path_to_trait_ref<'a,'tcx,AC,RS>(
-    this: &AC,
-    rscope: &RS,
+fn ast_path_to_trait_ref<'a,'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     trait_def_id: ast::DefId,
     self_ty: Option<Ty<'tcx>>,
     path: &ast::Path,
     mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
     -> Rc<ty::TraitRef<'tcx>>
-    where AC: AstConv<'tcx>, RS: RegionScope
 {
     debug!("ast_path_to_trait_ref {}", path);
     let trait_def = this.get_trait_def(trait_def_id);
@@ -632,7 +627,8 @@ fn ast_path_to_trait_ref<'a,'tcx,AC,RS>(
         }
         Some(ref mut v) => {
             for binding in assoc_bindings.iter() {
-                match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), binding) {
+                match ast_type_binding_to_projection_predicate(this, trait_ref.clone(),
+                                                               self_ty, binding) {
                     Ok(pp) => { v.push(pp); }
                     Err(ErrorReported) => { }
                 }
@@ -643,13 +639,15 @@ fn ast_path_to_trait_ref<'a,'tcx,AC,RS>(
     trait_ref
 }
 
-pub fn ast_type_binding_to_projection_predicate<'tcx,AC>(
-    this: &AC,
-    trait_ref: Rc<ty::TraitRef<'tcx>>,
+fn ast_type_binding_to_projection_predicate<'tcx>(
+    this: &AstConv<'tcx>,
+    mut trait_ref: Rc<ty::TraitRef<'tcx>>,
+    self_ty: Option<Ty<'tcx>>,
     binding: &ConvertedBinding<'tcx>)
     -> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
-    where AC : AstConv<'tcx>
 {
+    let tcx = this.tcx();
+
     // Given something like `U : SomeTrait<T=X>`, we want to produce a
     // predicate like `<U as SomeTrait>::T = X`. This is somewhat
     // subtle in the event that `T` is defined in a supertrait of
@@ -666,29 +664,93 @@ pub fn ast_type_binding_to_projection_predicate<'tcx,AC>(
     //
     // We want to produce `<B as SuperTrait<int>>::T == foo`.
 
-    // FIXME(#19541): supertrait upcasting not actually impl'd :)
+    // Simple case: X is defined in the current trait.
+    if trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) {
+        return Ok(ty::ProjectionPredicate {
+            projection_ty: ty::ProjectionTy {
+                trait_ref: trait_ref,
+                item_name: binding.item_name,
+            },
+            ty: binding.ty,
+        });
+    }
 
-    if !trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) {
-        this.tcx().sess.span_err(
+    // Otherwise, we have to walk through the supertraits to find
+    // those that do.  This is complicated by the fact that, for an
+    // object type, the `Self` type is not present in the
+    // substitutions (after all, it's being constructed right now),
+    // but the `supertraits` iterator really wants one. To handle
+    // this, we currently insert a dummy type and then remove it
+    // later. Yuck.
+
+    let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0));
+    if self_ty.is_none() { // if converting for an object type
+        let mut dummy_substs = trait_ref.substs.clone();
+        assert!(dummy_substs.self_ty().is_none());
+        dummy_substs.types.push(SelfSpace, dummy_self_ty);
+        trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id,
+                                              tcx.mk_substs(dummy_substs)));
+    }
+
+    let mut candidates: Vec<ty::PolyTraitRef> =
+        traits::supertraits(tcx, trait_ref.to_poly_trait_ref())
+        .filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name))
+        .collect();
+
+    // If converting for an object type, then remove the dummy-ty from `Self` now.
+    // Yuckety yuck.
+    if self_ty.is_none() {
+        for candidate in candidates.iter_mut() {
+            let mut dummy_substs = candidate.0.substs.clone();
+            assert!(dummy_substs.self_ty() == Some(dummy_self_ty));
+            dummy_substs.types.pop(SelfSpace);
+            *candidate = ty::Binder(Rc::new(ty::TraitRef::new(candidate.def_id(),
+                                                              tcx.mk_substs(dummy_substs))));
+        }
+    }
+
+    if candidates.len() > 1 {
+        tcx.sess.span_err(
             binding.span,
-            format!("no associated type `{}` defined in `{}`",
+            format!("ambiguous associated type: `{}` defined in multiple supertraits `{}`",
                     token::get_name(binding.item_name),
-                    trait_ref.user_string(this.tcx())).as_slice());
+                    candidates.user_string(tcx)).as_slice());
+        return Err(ErrorReported);
+    }
+
+    let candidate = match candidates.pop() {
+        Some(c) => c,
+        None => {
+            tcx.sess.span_err(
+                binding.span,
+                format!("no associated type `{}` defined in `{}`",
+                        token::get_name(binding.item_name),
+                        trait_ref.user_string(tcx)).as_slice());
+            return Err(ErrorReported);
+        }
+    };
+
+    if ty::binds_late_bound_regions(tcx, &candidate) {
+        tcx.sess.span_err(
+            binding.span,
+            format!("associated type `{}` defined in higher-ranked supertrait `{}`",
+                    token::get_name(binding.item_name),
+                    candidate.user_string(tcx)).as_slice());
         return Err(ErrorReported);
     }
 
     Ok(ty::ProjectionPredicate {
         projection_ty: ty::ProjectionTy {
-            trait_ref: trait_ref,
+            trait_ref: candidate.0,
             item_name: binding.item_name,
         },
         ty: binding.ty,
     })
 }
 
-pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
-    this: &AC,
-    rscope: &RS,
+pub fn ast_path_to_ty<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     did: ast::DefId,
     path: &ast::Path)
     -> TypeAndSubsts<'tcx>
@@ -712,13 +774,12 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
 /// and/or region variables are substituted.
 ///
 /// This is used when checking the constructor in struct literals.
-pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
-    this: &AC,
-    rscope: &RS,
+pub fn ast_path_to_ty_relaxed<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     did: ast::DefId,
     path: &ast::Path)
     -> TypeAndSubsts<'tcx>
-    where AC : AstConv<'tcx>, RS : RegionScope
 {
     let tcx = this.tcx();
     let ty::TypeScheme {
@@ -754,9 +815,9 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
 
 /// Converts the given AST type to a built-in type. A "built-in type" is, at
 /// present, either a core numeric type, a string, or `Box`.
-pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
-        this: &AC,
-        rscope: &RS,
+pub fn ast_ty_to_builtin_ty<'tcx>(
+        this: &AstConv<'tcx>,
+        rscope: &RegionScope,
         ast_ty: &ast::Ty)
         -> Option<Ty<'tcx>> {
     match ast_ty_to_prim_ty(this.tcx(), ast_ty) {
@@ -807,12 +868,11 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
 
 type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>);
 
-fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC,
-                                   rscope: &RS,
-                                   ty: &ast::Ty,
-                                   bounds: &[ast::TyParamBound])
-                                   -> Result<TraitAndProjections<'tcx>, ErrorReported>
-    where AC : AstConv<'tcx>, RS : RegionScope
+fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
+                             rscope: &RegionScope,
+                             ty: &ast::Ty,
+                             bounds: &[ast::TyParamBound])
+                             -> Result<TraitAndProjections<'tcx>, ErrorReported>
 {
     /*!
      * In a type like `Foo + Send`, we want to wait to collect the
@@ -878,14 +938,13 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC,
     }
 }
 
-fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC,
-                                        rscope: &RS,
-                                        span: Span,
-                                        trait_ref: ty::PolyTraitRef<'tcx>,
-                                        projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
-                                        bounds: &[ast::TyParamBound])
-                                        -> Ty<'tcx>
-    where AC : AstConv<'tcx>, RS : RegionScope
+fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
+                                  rscope: &RegionScope,
+                                  span: Span,
+                                  trait_ref: ty::PolyTraitRef<'tcx>,
+                                  projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
+                                  bounds: &[ast::TyParamBound])
+                                  -> Ty<'tcx>
 {
     let existential_bounds = conv_existential_bounds(this,
                                                      rscope,
@@ -909,6 +968,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
 {
     let tcx = this.tcx();
     let ty_param_def_id = provenance.def_id();
+
     let mut suitable_bounds: Vec<_>;
     let ty_param_name: ast::Name;
     { // contain scope of refcell:
@@ -916,13 +976,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
         let ty_param_def = &ty_param_defs[ty_param_def_id.node];
         ty_param_name = ty_param_def.name;
 
-        // FIXME(#19541): we should consider associated types in
-        // super-traits. Probably by elaborating the bounds.
-
+        // FIXME(#20300) -- search where clauses, not bounds
         suitable_bounds =
-            ty_param_def.bounds.trait_bounds // FIXME(#20300) -- search where clauses, not bounds
-            .iter()
-            .cloned()
+            traits::transitive_bounds(tcx, ty_param_def.bounds.trait_bounds.as_slice())
             .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
             .collect();
     }
@@ -963,12 +1019,11 @@ fn trait_defines_associated_type_named(this: &AstConv,
     trait_def.associated_type_names.contains(&assoc_name)
 }
 
-fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
-                           rscope: &RS,
-                           ast_ty: &ast::Ty, // the TyQPath
-                           qpath: &ast::QPath)
-                           -> Ty<'tcx>
-    where AC: AstConv<'tcx>, RS: RegionScope
+fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
+                     rscope: &RegionScope,
+                     ast_ty: &ast::Ty, // the TyQPath
+                     qpath: &ast::QPath)
+                     -> Ty<'tcx>
 {
     debug!("qpath_to_ty(ast_ty={})",
            ast_ty.repr(this.tcx()));
@@ -992,8 +1047,8 @@ fn qpath_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<'tcx>
+pub fn ast_ty_to_ty<'tcx>(
+        this: &AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx>
 {
     debug!("ast_ty_to_ty(ast_ty={})",
            ast_ty.repr(this.tcx()));
@@ -1205,10 +1260,12 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
     return typ;
 }
 
-pub fn ty_of_arg<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(this: &AC, rscope: &RS,
-                                                           a: &ast::Arg,
-                                                           expected_ty: Option<Ty<'tcx>>)
-                                                           -> Ty<'tcx> {
+pub fn ty_of_arg<'tcx>(this: &AstConv<'tcx>,
+                       rscope: &RegionScope,
+                       a: &ast::Arg,
+                       expected_ty: Option<Ty<'tcx>>)
+                       -> Ty<'tcx>
+{
     match a.ty.node {
         ast::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
         ast::TyInfer => this.ty_infer(a.ty.span),
@@ -1221,14 +1278,13 @@ struct SelfInfo<'a, 'tcx> {
     explicit_self: &'a ast::ExplicitSelf,
 }
 
-pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>(
-                    this: &AC,
-                    unsafety: ast::Unsafety,
-                    untransformed_self_ty: Ty<'tcx>,
-                    explicit_self: &ast::ExplicitSelf,
-                    decl: &ast::FnDecl,
-                    abi: abi::Abi)
-                    -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
+pub fn ty_of_method<'tcx>(this: &AstConv<'tcx>,
+                          unsafety: ast::Unsafety,
+                          untransformed_self_ty: Ty<'tcx>,
+                          explicit_self: &ast::ExplicitSelf,
+                          decl: &ast::FnDecl,
+                          abi: abi::Abi)
+                          -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
     let self_info = Some(SelfInfo {
         untransformed_self_ty: untransformed_self_ty,
         explicit_self: explicit_self,
@@ -1242,20 +1298,18 @@ pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>(
     (bare_fn_ty, optional_explicit_self_category.unwrap())
 }
 
-pub fn ty_of_bare_fn<'tcx, AC: AstConv<'tcx>>(this: &AC, unsafety: ast::Unsafety, abi: abi::Abi,
+pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi,
                                               decl: &ast::FnDecl) -> ty::BareFnTy<'tcx> {
     let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, unsafety, abi, None, decl);
     bare_fn_ty
 }
 
-fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
-                           this: &AC,
-                           unsafety: ast::Unsafety,
-                           abi: abi::Abi,
-                           opt_self_info: Option<SelfInfo<'a, 'tcx>>,
-                           decl: &ast::FnDecl)
-                           -> (ty::BareFnTy<'tcx>,
-                               Option<ty::ExplicitSelfCategory>)
+fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
+                                     unsafety: ast::Unsafety,
+                                     abi: abi::Abi,
+                                     opt_self_info: Option<SelfInfo<'a, 'tcx>>,
+                                     decl: &ast::FnDecl)
+                                     -> (ty::BareFnTy<'tcx>, Option<ty::ExplicitSelfCategory>)
 {
     debug!("ty_of_method_or_bare_fn");
 
@@ -1357,12 +1411,10 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>(
     }, explicit_self_category_result)
 }
 
-fn determine_explicit_self_category<'a, 'tcx, AC: AstConv<'tcx>,
-                                    RS:RegionScope>(
-                                    this: &AC,
-                                    rscope: &RS,
-                                    self_info: &SelfInfo<'a, 'tcx>)
-                                    -> ty::ExplicitSelfCategory
+fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>,
+                                              rscope: &RegionScope,
+                                              self_info: &SelfInfo<'a, 'tcx>)
+                                              -> ty::ExplicitSelfCategory
 {
     return match self_info.explicit_self.node {
         ast::SelfStatic => ty::StaticExplicitSelfCategory,
@@ -1439,8 +1491,8 @@ fn determine_explicit_self_category<'a, 'tcx, AC: AstConv<'tcx>,
     }
 }
 
-pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
-    this: &AC,
+pub fn ty_of_closure<'tcx>(
+    this: &AstConv<'tcx>,
     unsafety: ast::Unsafety,
     onceness: ast::Onceness,
     bounds: ty::ExistentialBounds<'tcx>,
@@ -1501,9 +1553,9 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
 /// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent
 /// for closures. Eventually this should all be normalized, I think, so that there is no "main
 /// trait ref" and instead we just have a flat list of bounds as the existential type.
-pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
-    this: &AC,
-    rscope: &RS,
+pub fn conv_existential_bounds<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     span: Span,
     principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
     projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
@@ -1517,13 +1569,12 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
         this, rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds)
 }
 
-fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
-    this: &AC,
-    rscope: &RS,
+fn conv_ty_poly_trait_ref<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     span: Span,
     ast_bounds: &[ast::TyParamBound])
     -> Ty<'tcx>
-    where AC: AstConv<'tcx>, RS:RegionScope
 {
     let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]);
 
@@ -1556,15 +1607,14 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
     }
 }
 
-pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>(
-    this: &AC,
-    rscope: &RS,
+pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     span: Span,
     principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
     mut projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures
     partitioned_bounds: PartitionedBounds)
     -> ty::ExistentialBounds<'tcx>
-    where AC: AstConv<'tcx>, RS:RegionScope
 {
     let PartitionedBounds { builtin_bounds,
                             trait_bounds,
@@ -1657,9 +1707,9 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
 /// A version of `compute_opt_region_bound` for use where some region bound is required
 /// (existential types, basically). Reports an error if no region bound can be derived and we are
 /// in an `rscope` that does not provide a default.
-fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
-    this: &AC,
-    rscope: &RS,
+fn compute_region_bound<'tcx>(
+    this: &AstConv<'tcx>,
+    rscope: &RegionScope,
     span: Span,
     region_bounds: &[&ast::Lifetime],
     principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for closures
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 854de823511..8b62c55ba31 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4939,7 +4939,7 @@ pub fn check_enum_variants(ccx: &CrateCtxt,
                 Some(i) => {
                     span_err!(ccx.tcx.sess, v.span, E0081,
                         "discriminant value `{}` already exists", disr_vals[i]);
-                    span_note!(ccx.tcx.sess, ccx.tcx().map.span(variants[i].id.node),
+                    span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].id.node),
                         "conflicting discriminant here")
                 }
                 None => {}
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 7c88404eb64..bbafcdae1bb 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -40,11 +40,12 @@ use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitCont
 use middle::ty::{self, RegionEscape, Ty, TypeScheme};
 use middle::ty_fold::{self, TypeFolder, TypeFoldable};
 use middle::infer;
+use no_params;
 use rscope::*;
-use {CrateCtxt, no_params, write_ty_to_tcx};
 use util::nodemap::{FnvHashMap, FnvHashSet};
 use util::ppaux;
 use util::ppaux::{Repr,UserString};
+use write_ty_to_tcx;
 
 use std::rc::Rc;
 
@@ -61,13 +62,8 @@ use syntax::visit;
 ///////////////////////////////////////////////////////////////////////////
 // Main entry point
 
-pub fn collect_item_types(ccx: &CrateCtxt) {
-    fn collect_intrinsic_type(ccx: &CrateCtxt,
-                              lang_item: ast::DefId) {
-        let ty::TypeScheme { ty, .. } =
-            ccx.get_item_type_scheme(lang_item);
-        ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty);
-    }
+pub fn collect_item_types(tcx: &ty::ctxt) {
+    let ccx = &CollectCtxt { tcx: tcx };
 
     match ccx.tcx.lang_items.ty_desc() {
         Some(id) => { collect_intrinsic_type(ccx, id); }
@@ -86,12 +82,28 @@ pub fn collect_item_types(ccx: &CrateCtxt) {
 }
 
 ///////////////////////////////////////////////////////////////////////////
+
+struct CollectCtxt<'a,'tcx:'a> {
+    tcx: &'a ty::ctxt<'tcx>,
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Zeroth phase: collect types of intrinsics
+
+fn collect_intrinsic_type(ccx: &CollectCtxt,
+                          lang_item: ast::DefId) {
+    let ty::TypeScheme { ty, .. } =
+        ccx.get_item_type_scheme(lang_item);
+    ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty);
+}
+
+///////////////////////////////////////////////////////////////////////////
 // First phase: just collect *trait definitions* -- basically, the set
 // of type parameters and supertraits. This is information we need to
 // know later when parsing field defs.
 
 struct CollectTraitDefVisitor<'a, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'tcx>
+    ccx: &'a CollectCtxt<'a, 'tcx>
 }
 
 impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> {
@@ -112,7 +124,7 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> {
 // Second phase: collection proper.
 
 struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
-    ccx: &'a CrateCtxt<'a, 'tcx>
+    ccx: &'a CollectCtxt<'a, 'tcx>
 }
 
 impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
@@ -133,13 +145,13 @@ pub trait ToTy<'tcx> {
     fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>;
 }
 
-impl<'a,'tcx> ToTy<'tcx> for CrateCtxt<'a,'tcx> {
+impl<'a,'tcx> ToTy<'tcx> for CollectCtxt<'a,'tcx> {
     fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> {
         ast_ty_to_ty(self, rs, ast_ty)
     }
 }
 
-impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> {
+impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> {
     fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
 
     fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> {
@@ -148,7 +160,9 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> {
         }
 
         match self.tcx.map.find(id.node) {
-            Some(ast_map::NodeItem(item)) => ty_of_item(self, &*item),
+            Some(ast_map::NodeItem(item)) => {
+                ty_of_item(self, &*item)
+            }
             Some(ast_map::NodeForeignItem(foreign_item)) => {
                 let abi = self.tcx.map.get_foreign_abi(id.node);
                 ty_of_foreign_item(self, &*foreign_item, abi)
@@ -181,7 +195,7 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> {
     }
 }
 
-pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                         enum_ty: Ty<'tcx>,
                                         variants: &[P<ast::Variant>],
                                         generics: &ast::Generics) {
@@ -226,7 +240,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                    trait_id: ast::NodeId,
                                    trait_def: &ty::TraitDef<'tcx>) {
     let tcx = ccx.tcx;
@@ -322,7 +336,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         }
     }
 
-    fn make_method_ty<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) {
+    fn make_method_ty<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) {
         ccx.tcx.tcache.borrow_mut().insert(
             m.def_id,
             TypeScheme {
@@ -330,7 +344,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), ccx.tcx.mk_bare_fn(m.fty.clone())) });
     }
 
-    fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+    fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                            trait_id: ast::NodeId,
                                            trait_generics: &ty::Generics<'tcx>,
                                            _trait_items: &[ast::TraitItem],
@@ -372,7 +386,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_field<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                 struct_generics: &ty::Generics<'tcx>,
                                 v: &ast::StructField,
                                 origin: ast::DefId) -> ty::field_ty {
@@ -405,7 +419,7 @@ pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_associated_type<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                      trait_def: &ty::TraitDef<'tcx>,
                                      associated_type: &ast::AssociatedType)
 {
@@ -422,7 +436,7 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                ty::TypeTraitItem(associated_type));
 }
 
-fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>,
                                  container: ImplOrTraitItemContainer,
                                  mut ms: I,
                                  untransformed_rcvr_ty: Ty<'tcx>,
@@ -469,7 +483,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
            .insert(mty.def_id, ty::MethodTraitItem(mty));
     }
 
-    fn ty_of_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+    fn ty_of_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                               container: ImplOrTraitItemContainer,
                               m: &ast::Method,
                               untransformed_rcvr_ty: Ty<'tcx>,
@@ -506,7 +520,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
+fn ensure_no_ty_param_bounds(ccx: &CollectCtxt,
                                  span: Span,
                                  generics: &ast::Generics,
                                  thing: &'static str) {
@@ -535,7 +549,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
     }
 }
 
-pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
+fn convert(ccx: &CollectCtxt, it: &ast::Item) {
     let tcx = ccx.tcx;
     debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id);
     match it.node {
@@ -636,7 +650,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
 
             debug!("trait_def: ident={} trait_def={}",
                    it.ident.repr(ccx.tcx),
-                   trait_def.repr(ccx.tcx()));
+                   trait_def.repr(ccx.tcx));
 
             for trait_method in trait_methods.iter() {
                 let self_type = ty::mk_self_type(tcx);
@@ -706,7 +720,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
     }
 }
 
-pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                 struct_def: &ast::StructDef,
                                 scheme: ty::TypeScheme<'tcx>,
                                 id: ast::NodeId) {
@@ -773,7 +787,7 @@ pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) {
+fn convert_foreign(ccx: &CollectCtxt, i: &ast::ForeignItem) {
     // As above, this call populates the type table with the converted
     // type of the foreign item. We simply write it into the node type
     // table.
@@ -790,7 +804,7 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) {
     ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), scheme);
 }
 
-fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                            trait_id: ast::DefId)
                            -> Rc<ty::TraitDef<'tcx>> {
     if trait_id.krate != ast::LOCAL_CRATE {
@@ -806,9 +820,9 @@ fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                   it: &ast::Item)
-                                   -> Rc<ty::TraitDef<'tcx>>
+fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+                               it: &ast::Item)
+                               -> Rc<ty::TraitDef<'tcx>>
 {
     let def_id = local_def(it.id);
     let tcx = ccx.tcx;
@@ -872,7 +886,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     return trait_def;
 
-    fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+    fn mk_trait_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                  generics: &ast::Generics)
                                  -> subst::Substs<'tcx>
     {
@@ -903,7 +917,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
+fn ty_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item)
                             -> ty::TypeScheme<'tcx> {
     let def_id = local_def(it.id);
     let tcx = ccx.tcx;
@@ -985,7 +999,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
     }
 }
 
-pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn ty_of_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                     it: &ast::ForeignItem,
                                     abi: abi::Abi) -> ty::TypeScheme<'tcx>
 {
@@ -1006,7 +1020,7 @@ pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                           generics: &ast::Generics)
                                           -> ty::Generics<'tcx> {
     ty_generics(ccx,
@@ -1017,7 +1031,7 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 &generics.where_clause)
 }
 
-fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                    trait_id: ast::NodeId,
                                    substs: &'tcx subst::Substs<'tcx>,
                                    ast_generics: &ast::Generics,
@@ -1077,7 +1091,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     return generics;
 
-    fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+    fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                                  self_trait_ref: &Rc<ty::TraitRef<'tcx>>,
                                                  trait_items: &[ast::TraitItem])
                                                  -> Vec<ty::Predicate<'tcx>>
@@ -1108,14 +1122,13 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn ty_generics_for_fn_or_method<'tcx,AC>(
-        this: &AC,
-        generics: &ast::Generics,
-        base_generics: ty::Generics<'tcx>)
-        -> ty::Generics<'tcx>
-        where AC: AstConv<'tcx> {
+fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                                         generics: &ast::Generics,
+                                         base_generics: ty::Generics<'tcx>)
+                                         -> ty::Generics<'tcx>
+{
     let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
-    ty_generics(this,
+    ty_generics(ccx,
                 subst::FnSpace,
                 early_lifetimes[],
                 generics.ty_params[],
@@ -1124,11 +1137,11 @@ fn ty_generics_for_fn_or_method<'tcx,AC>(
 }
 
 // Add the Sized bound, unless the type parameter is marked as `?Sized`.
-fn add_unsized_bound<'tcx,AC>(this: &AC,
+fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                               bounds: &mut ty::BuiltinBounds,
                               ast_bounds: &[ast::TyParamBound],
                               span: Span)
-                              where AC: AstConv<'tcx> {
+{
     // Try to find an unbound in bounds.
     let mut unbound = None;
     for ab in ast_bounds.iter() {
@@ -1137,24 +1150,24 @@ fn add_unsized_bound<'tcx,AC>(this: &AC,
                 assert!(ptr.bound_lifetimes.is_empty());
                 unbound = Some(ptr.trait_ref.clone());
             } else {
-                this.tcx().sess.span_err(span, "type parameter has more than one relaxed default \
+                ccx.tcx.sess.span_err(span, "type parameter has more than one relaxed default \
                                                 bound, only one is supported");
             }
         }
     }
 
-    let kind_id = this.tcx().lang_items.require(SizedTraitLangItem);
+    let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem);
     match unbound {
         Some(ref tpb) => {
             // FIXME(#8559) currently requires the unbound to be built-in.
-            let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb);
+            let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb);
             match kind_id {
                 Ok(kind_id) if trait_def_id != kind_id => {
-                    this.tcx().sess.span_warn(span,
+                    ccx.tcx.sess.span_warn(span,
                                               "default bound relaxed for a type parameter, but \
                                                this does nothing because the given bound is not \
                                                a default. Only `?Sized` is supported");
-                    ty::try_add_builtin_trait(this.tcx(),
+                    ty::try_add_builtin_trait(ccx.tcx,
                                               kind_id,
                                               bounds);
                 }
@@ -1162,27 +1175,26 @@ fn add_unsized_bound<'tcx,AC>(this: &AC,
             }
         }
         _ if kind_id.is_ok() => {
-            ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds);
+            ty::try_add_builtin_trait(ccx.tcx, kind_id.unwrap(), bounds);
         }
         // No lang item for Sized, so we can't add it as a bound.
         None => {}
     }
 }
 
-fn ty_generics<'tcx,AC>(this: &AC,
+fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                         space: subst::ParamSpace,
                         lifetime_defs: &[ast::LifetimeDef],
                         types: &[ast::TyParam],
                         base_generics: ty::Generics<'tcx>,
                         where_clause: &ast::WhereClause)
                         -> ty::Generics<'tcx>
-                        where AC: AstConv<'tcx>
 {
     let mut result = base_generics;
 
     for (i, l) in lifetime_defs.iter().enumerate() {
         let bounds = l.bounds.iter()
-                             .map(|l| ast_region_to_region(this.tcx(), l))
+                             .map(|l| ast_region_to_region(ccx.tcx, l))
                              .collect();
         let def = ty::RegionParameterDef { name: l.lifetime.name,
                                            space: space,
@@ -1197,25 +1209,25 @@ fn ty_generics<'tcx,AC>(this: &AC,
 
     // Now create the real type parameters.
     for (i, param) in types.iter().enumerate() {
-        let def = get_or_create_type_parameter_def(this,
+        let def = get_or_create_type_parameter_def(ccx,
                                                    space,
                                                    param,
                                                    i as u32);
         debug!("ty_generics: def for type param: {}, {}",
-               def.repr(this.tcx()),
+               def.repr(ccx.tcx),
                space);
         result.types.push(space, def);
     }
 
     // Just for fun, also push the bounds from the type parameters
     // into the predicates list. This is currently kind of non-DRY.
-    create_predicates(this.tcx(), &mut result, space);
+    create_predicates(ccx.tcx, &mut result, space);
 
     // Add the bounds not associated with a type parameter
     for predicate in where_clause.predicates.iter() {
         match predicate {
             &ast::WherePredicate::BoundPredicate(ref bound_pred) => {
-                let ty = ast_ty_to_ty(this, &ExplicitRscope, &*bound_pred.bounded_ty);
+                let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*bound_pred.bounded_ty);
 
                 for bound in bound_pred.bounds.iter() {
                     match bound {
@@ -1223,7 +1235,7 @@ fn ty_generics<'tcx,AC>(this: &AC,
                             let mut projections = Vec::new();
 
                             let trait_ref = astconv::instantiate_poly_trait_ref(
-                                this,
+                                ccx,
                                 &ExplicitRscope,
                                 poly_trait_ref,
                                 Some(ty),
@@ -1238,7 +1250,7 @@ fn ty_generics<'tcx,AC>(this: &AC,
                         }
 
                         &ast::TyParamBound::RegionTyParamBound(ref lifetime) => {
-                            let region = ast_region_to_region(this.tcx(), lifetime);
+                            let region = ast_region_to_region(ccx.tcx, lifetime);
                             let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
                             result.predicates.push(space, ty::Predicate::TypeOutlives(pred))
                         }
@@ -1247,9 +1259,9 @@ fn ty_generics<'tcx,AC>(this: &AC,
             }
 
             &ast::WherePredicate::RegionPredicate(ref region_pred) => {
-                let r1 = ast_region_to_region(this.tcx(), &region_pred.lifetime);
+                let r1 = ast_region_to_region(ccx.tcx, &region_pred.lifetime);
                 for bound in region_pred.bounds.iter() {
-                    let r2 = ast_region_to_region(this.tcx(), bound);
+                    let r2 = ast_region_to_region(ccx.tcx, bound);
                     let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
                     result.predicates.push(space, ty::Predicate::RegionOutlives(pred))
                 }
@@ -1257,7 +1269,7 @@ fn ty_generics<'tcx,AC>(this: &AC,
 
             &ast::WherePredicate::EqPredicate(ref eq_pred) => {
                 // FIXME(#20041)
-                this.tcx().sess.span_bug(eq_pred.span,
+                ccx.tcx.sess.span_bug(eq_pred.span,
                                          "Equality constraints are not yet \
                                             implemented (#20041)")
             }
@@ -1292,34 +1304,33 @@ fn ty_generics<'tcx,AC>(this: &AC,
     }
 }
 
-fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC,
+fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                                              space: subst::ParamSpace,
                                              param: &ast::TyParam,
                                              index: u32)
                                              -> ty::TypeParameterDef<'tcx>
-    where AC: AstConv<'tcx>
 {
-    match this.tcx().ty_param_defs.borrow().get(&param.id) {
+    match ccx.tcx.ty_param_defs.borrow().get(&param.id) {
         Some(d) => { return (*d).clone(); }
         None => { }
     }
 
     let param_ty = ty::ParamTy::new(space, index, param.ident.name);
-    let bounds = compute_bounds(this,
-                                param_ty.to_ty(this.tcx()),
+    let bounds = compute_bounds(ccx,
+                                param_ty.to_ty(ccx.tcx),
                                 param.bounds[],
                                 SizedByDefault::Yes,
                                 param.span);
     let default = match param.default {
         None => None,
         Some(ref path) => {
-            let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path);
+            let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &**path);
             let cur_idx = index;
 
             ty::walk_ty(ty, |t| {
                 match t.sty {
                     ty::ty_param(p) => if p.idx > cur_idx {
-                        span_err!(this.tcx().sess, path.span, E0128,
+                        span_err!(ccx.tcx.sess, path.span, E0128,
                                   "type parameters with a default cannot use \
                                    forward declared identifiers");
                         },
@@ -1340,7 +1351,7 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC,
         default: default
     };
 
-    this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone());
+    ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
 
     def
 }
@@ -1350,26 +1361,25 @@ enum SizedByDefault { Yes, No }
 /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
 /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
 /// built-in trait (formerly known as kind): Send.
-fn compute_bounds<'tcx,AC>(this: &AC,
+fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                            param_ty: ty::Ty<'tcx>,
                            ast_bounds: &[ast::TyParamBound],
                            sized_by_default: SizedByDefault,
                            span: Span)
                            -> ty::ParamBounds<'tcx>
-                           where AC: AstConv<'tcx>
 {
-    let mut param_bounds = conv_param_bounds(this,
+    let mut param_bounds = conv_param_bounds(ccx,
                                              span,
                                              param_ty,
                                              ast_bounds);
 
     if let SizedByDefault::Yes = sized_by_default {
-        add_unsized_bound(this,
+        add_unsized_bound(ccx,
                           &mut param_bounds.builtin_bounds,
                           ast_bounds,
                           span);
 
-        check_bounds_compatible(this.tcx(),
+        check_bounds_compatible(ccx.tcx,
                                 param_ty,
                                 &param_bounds,
                                 span);
@@ -1404,24 +1414,23 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>,
     }
 }
 
-fn conv_param_bounds<'tcx,AC>(this: &AC,
+fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                               span: Span,
                               param_ty: ty::Ty<'tcx>,
                               ast_bounds: &[ast::TyParamBound])
                               -> ty::ParamBounds<'tcx>
-                              where AC: AstConv<'tcx>
 {
     let astconv::PartitionedBounds { builtin_bounds,
                                      trait_bounds,
                                      region_bounds } =
-        astconv::partition_bounds(this.tcx(), span, ast_bounds.as_slice());
+        astconv::partition_bounds(ccx.tcx, span, ast_bounds.as_slice());
 
     let mut projection_bounds = Vec::new();
 
     let trait_bounds: Vec<ty::PolyTraitRef> =
         trait_bounds.into_iter()
         .map(|bound| {
-            astconv::instantiate_poly_trait_ref(this,
+            astconv::instantiate_poly_trait_ref(ccx,
                                                 &ExplicitRscope,
                                                 bound,
                                                 Some(param_ty),
@@ -1430,7 +1439,7 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
         .collect();
     let region_bounds: Vec<ty::Region> =
         region_bounds.into_iter()
-        .map(|r| ast_region_to_region(this.tcx(), r))
+        .map(|r| ast_region_to_region(ccx.tcx, r))
         .collect();
     ty::ParamBounds {
         region_bounds: region_bounds,
@@ -1440,7 +1449,7 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
     }
 }
 
-pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                        decl: &ast::FnDecl,
                                        def_id: ast::DefId,
                                        ast_generics: &ast::Generics,
@@ -1492,9 +1501,9 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     return scheme;
 }
 
-pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                ty_generics: &ty::Generics<'tcx>)
-                                -> subst::Substs<'tcx>
+fn mk_item_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+                            ty_generics: &ty::Generics<'tcx>)
+                            -> subst::Substs<'tcx>
 {
     let types =
         ty_generics.types.map(
@@ -1514,14 +1523,14 @@ pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 /// comes back to check after the fact that explicit type the user
 /// wrote actually matches what the pre-defined option said.
 fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
-    crate_context: &CrateCtxt<'a, 'tcx>,
+    ccx: &CollectCtxt<'a, 'tcx>,
     rs: &RS,
     required_type: Ty<'tcx>,
     explicit_self: &ast::ExplicitSelf,
     body_id: ast::NodeId)
 {
     if let ast::SelfExplicit(ref ast_type, _) = explicit_self.node {
-        let typ = crate_context.to_ty(rs, &**ast_type);
+        let typ = ccx.to_ty(rs, &**ast_type);
         let base_type = match typ.sty {
             ty::ty_ptr(tm) | ty::ty_rptr(_, tm) => tm.ty,
             ty::ty_uniq(typ) => typ,
@@ -1537,27 +1546,27 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
         assert!(!base_type.has_regions_escaping_depth(1));
         let required_type_free =
             liberate_early_bound_regions(
-                crate_context.tcx, body_scope,
+                ccx.tcx, body_scope,
                 &ty::liberate_late_bound_regions(
-                    crate_context.tcx, body_scope, &ty::Binder(required_type)));
+                    ccx.tcx, body_scope, &ty::Binder(required_type)));
 
         // The "base type" comes from the impl. It too may have late-bound
         // regions from the method.
         assert!(!base_type.has_regions_escaping_depth(1));
         let base_type_free =
             liberate_early_bound_regions(
-                crate_context.tcx, body_scope,
+                ccx.tcx, body_scope,
                 &ty::liberate_late_bound_regions(
-                    crate_context.tcx, body_scope, &ty::Binder(base_type)));
+                    ccx.tcx, body_scope, &ty::Binder(base_type)));
 
         debug!("required_type={} required_type_free={} \
                 base_type={} base_type_free={}",
-               required_type.repr(crate_context.tcx),
-               required_type_free.repr(crate_context.tcx),
-               base_type.repr(crate_context.tcx),
-               base_type_free.repr(crate_context.tcx));
-        let infcx = infer::new_infer_ctxt(crate_context.tcx);
-        drop(::require_same_types(crate_context.tcx,
+               required_type.repr(ccx.tcx),
+               required_type_free.repr(ccx.tcx),
+               base_type.repr(ccx.tcx),
+               base_type_free.repr(ccx.tcx));
+        let infcx = infer::new_infer_ctxt(ccx.tcx);
+        drop(::require_same_types(ccx.tcx,
                                   Some(&infcx),
                                   false,
                                   explicit_self.span,
@@ -1565,7 +1574,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
                                   required_type_free,
                                   || {
                 format!("mismatched self type: expected `{}`",
-                        ppaux::ty_to_string(crate_context.tcx, required_type))
+                        ppaux::ty_to_string(ccx.tcx, required_type))
         }));
         infcx.resolve_regions_and_report_errors(body_id);
     }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 48f9b129719..3146a118139 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -119,7 +119,7 @@ struct TypeAndSubsts<'tcx> {
 struct CrateCtxt<'a, 'tcx: 'a> {
     // A mapping from method call sites to traits that have that method.
     trait_map: ty::TraitMap,
-    tcx: &'a ty::ctxt<'tcx>
+    tcx: &'a ty::ctxt<'tcx>,
 }
 
 // Functions that write types into the node type table
@@ -320,7 +320,7 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
     };
 
     time(time_passes, "type collecting", (), |_|
-        collect::collect_item_types(&ccx));
+         collect::collect_item_types(tcx));
 
     // this ensures that later parts of type checking can assume that items
     // have valid types and not error
diff --git a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs
new file mode 100644
index 00000000000..6555aa32027
--- /dev/null
+++ b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs
@@ -0,0 +1,47 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test equality constraints in a where clause where the type being
+// equated appears in a supertrait.
+
+#![feature(associated_types)]
+
+pub trait Vehicle {
+    type Color;
+
+    fn go(&self) {  }
+}
+
+pub trait Box {
+    type Color;
+
+    fn mail(&self) {  }
+}
+
+pub trait BoxCar : Box + Vehicle {
+}
+
+fn dent<C:BoxCar>(c: C, color: C::Color) {
+    //~^ ERROR ambiguous associated type `Color` in bounds of `C`
+    //~| NOTE could derive from `Vehicle`
+    //~| NOTE could derive from `Box`
+}
+
+fn dent_object<COLOR>(c: BoxCar<Color=COLOR>) {
+    //~^ ERROR ambiguous associated type
+}
+
+fn paint<C:BoxCar>(c: C, d: C::Color) {
+    //~^ ERROR ambiguous associated type `Color` in bounds of `C`
+    //~| NOTE could derive from `Vehicle`
+    //~| NOTE could derive from `Box`
+}
+
+pub fn main() { }
diff --git a/src/test/compile-fail/associated-type-projection-from-supertrait.rs b/src/test/compile-fail/associated-type-projection-from-supertrait.rs
new file mode 100644
index 00000000000..01f9bd3541f
--- /dev/null
+++ b/src/test/compile-fail/associated-type-projection-from-supertrait.rs
@@ -0,0 +1,56 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test equality constraints in a where clause where the type being
+// equated appears in a supertrait.
+
+#![feature(associated_types)]
+
+pub trait Vehicle {
+    type Color;
+
+    fn go(&self) {  }
+}
+
+pub trait Car : Vehicle {
+    fn honk(&self) { }
+    fn chip_paint(&self, c: Self::Color) { }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+struct Black;
+struct ModelT;
+impl Vehicle for ModelT { type Color = Black; }
+impl Car for ModelT { }
+
+///////////////////////////////////////////////////////////////////////////
+
+struct Blue;
+struct ModelU;
+impl Vehicle for ModelU { type Color = Blue; }
+impl Car for ModelU { }
+
+///////////////////////////////////////////////////////////////////////////
+
+fn dent<C:Car>(c: C, color: C::Color) { c.chip_paint(color) }
+fn a() { dent(ModelT, Black); }
+fn b() { dent(ModelT, Blue); } //~ ERROR type mismatch
+fn c() { dent(ModelU, Black); } //~ ERROR type mismatch
+fn d() { dent(ModelU, Blue); }
+
+///////////////////////////////////////////////////////////////////////////
+
+fn e() { ModelT.chip_paint(Black); }
+fn f() { ModelT.chip_paint(Blue); } //~ ERROR mismatched types
+fn g() { ModelU.chip_paint(Black); } //~ ERROR mismatched types
+fn h() { ModelU.chip_paint(Blue); }
+
+pub fn main() { }
diff --git a/src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs b/src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs
new file mode 100644
index 00000000000..a362529bee8
--- /dev/null
+++ b/src/test/compile-fail/associated-types-binding-to-type-defined-in-supertrait.rs
@@ -0,0 +1,53 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test equality constraints in a where clause where the type being
+// equated appears in a supertrait.
+
+#![feature(associated_types)]
+
+pub trait Vehicle {
+    type Color;
+
+    fn go(&self) {  }
+}
+
+pub trait Car : Vehicle {
+    fn honk(&self) { }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+struct Black;
+struct ModelT;
+impl Vehicle for ModelT { type Color = Black; }
+impl Car for ModelT { }
+
+///////////////////////////////////////////////////////////////////////////
+
+struct Blue;
+struct ModelU;
+impl Vehicle for ModelU { type Color = Blue; }
+impl Car for ModelU { }
+
+///////////////////////////////////////////////////////////////////////////
+
+fn black_car<C:Car<Color=Black>>(c: C) {
+}
+
+fn blue_car<C:Car<Color=Blue>>(c: C) {
+}
+
+fn a() { black_car(ModelT); }
+fn b() { blue_car(ModelT); } //~ ERROR type mismatch
+fn c() { black_car(ModelU); } //~ ERROR type mismatch
+fn d() { blue_car(ModelU); }
+
+pub fn main() { }
diff --git a/src/test/run-pass/associated-type-doubleendediterator-object.rs b/src/test/run-pass/associated-type-doubleendediterator-object.rs
new file mode 100644
index 00000000000..429027cbf30
--- /dev/null
+++ b/src/test/run-pass/associated-type-doubleendediterator-object.rs
@@ -0,0 +1,27 @@
+// 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.
+
+fn pairwise_sub(mut t: Box<DoubleEndedIterator<Item=int>>) -> int {
+    let mut result = 0;
+    loop {
+        let front = t.next();
+        let back = t.next_back();
+        match (front, back) {
+            (Some(f), Some(b)) => { result += b - f; }
+            _ => { return result; }
+        }
+    }
+}
+
+fn main() {
+    let v = vec!(1, 2, 3, 4, 5, 6);
+    let r = pairwise_sub(box v.into_iter());
+    assert_eq!(r, 9);
+}
diff --git a/src/test/run-pass/associated-types-iterator-binding.rs b/src/test/run-pass/associated-types-iterator-binding.rs
new file mode 100644
index 00000000000..f8258466a7d
--- /dev/null
+++ b/src/test/run-pass/associated-types-iterator-binding.rs
@@ -0,0 +1,27 @@
+// 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.
+
+fn pairwise_sub<T:DoubleEndedIterator<Item=int>>(mut t: T) -> int {
+    let mut result = 0;
+    loop {
+        let front = t.next();
+        let back = t.next_back();
+        match (front, back) {
+            (Some(f), Some(b)) => { result += b - f; }
+            _ => { return result; }
+        }
+    }
+}
+
+fn main() {
+    let v = vec!(1, 2, 3, 4, 5, 6);
+    let r =pairwise_sub(v.into_iter());
+    assert_eq!(r, 9);
+}