From 15ef2c2e6b94e8430d718a13c9845e33989a50d6 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Tue, 17 Feb 2015 11:04:25 -0500
Subject: [PATCH] Convert `astconv` to request bounds through the `AstConv`
 interface rather than poking through the `TypeParameterDef` directly.

---
 src/librustc/middle/ty.rs        |  9 ++++++++-
 src/librustc_typeck/astconv.rs   |  8 ++++++--
 src/librustc_typeck/check/mod.rs | 26 +++++++++++++++++++++++++-
 src/librustc_typeck/collect.rs   | 19 ++++++++++++++++---
 4 files changed, 55 insertions(+), 7 deletions(-)

diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 91313633397..275007bf797 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -55,7 +55,7 @@ use middle::region;
 use middle::resolve_lifetime;
 use middle::infer;
 use middle::stability;
-use middle::subst::{self, Subst, Substs, VecPerParamSpace};
+use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
 use middle::traits;
 use middle::ty;
 use middle::ty_fold::{self, TypeFoldable, TypeFolder};
@@ -2996,6 +2996,13 @@ impl<'tcx> TyS<'tcx> {
             _ => None,
         }
     }
+
+    pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
+        match self.sty {
+            ty::ty_param(ref data) => data.space == space && data.idx == index,
+            _ => false,
+        }
+    }
 }
 
 pub fn walk_ty<'tcx, F>(ty_root: Ty<'tcx>, mut f: F)
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 9e50fdb4c48..d0e194e15d2 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -53,7 +53,7 @@ use middle::const_eval;
 use middle::def;
 use middle::resolve_lifetime as rl;
 use middle::privacy::{AllPublic, LastMod};
-use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
+use middle::subst::{FnSpace, ParamSpace, TypeSpace, SelfSpace, Subst, Substs};
 use middle::traits;
 use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
@@ -77,6 +77,8 @@ pub trait AstConv<'tcx> {
 
     fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>;
 
+    fn get_type_parameter_bounds(&self, space: ParamSpace, index: u32) -> Vec<ty::PolyTraitRef<'tcx>>;
+
     /// Return an (optional) substitution to convert bound type parameters that
     /// are in scope into free ones. This function should only return Some
     /// within a fn body.
@@ -1011,7 +1013,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
 
         // FIXME(#20300) -- search where clauses, not bounds
         suitable_bounds =
-            traits::transitive_bounds(tcx, &ty_param_def.bounds.trait_bounds)
+            traits::transitive_bounds(tcx,
+                                      &this.get_type_parameter_bounds(ty_param_def.space,
+                                                                      ty_param_def.index))
             .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
             .collect();
     }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d7a11b8a515..968d67aca9d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -97,7 +97,7 @@ use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace
 use middle::traits;
 use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme};
 use middle::ty::{Disr, ParamTy, ParameterEnvironment};
-use middle::ty::{self, HasProjectionTypes, RegionEscape, Ty};
+use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty};
 use middle::ty::liberate_late_bound_regions;
 use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
 use middle::ty_fold::{TypeFolder, TypeFoldable};
@@ -1218,6 +1218,30 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         Some(&self.inh.param_env.free_substs)
     }
 
+    fn get_type_parameter_bounds(&self,
+                                 space: ParamSpace,
+                                 index: u32)
+                                 -> Vec<ty::PolyTraitRef<'tcx>>
+    {
+        self.inh.param_env.caller_bounds
+                          .iter()
+                          .filter_map(|predicate| {
+                              match *predicate {
+                                  ty::Predicate::Trait(ref data) => {
+                                      if data.0.self_ty().is_param(space, index) {
+                                          Some(data.to_poly_trait_ref())
+                                      } else {
+                                          None
+                                      }
+                                  }
+                                  _ => {
+                                      None
+                                  }
+                              }
+                          })
+                          .collect()
+    }
+
     fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
         self.infcx().next_ty_var()
     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 3ca12959246..6d65d05bf6f 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -145,7 +145,6 @@ struct CrateCtxt<'a,'tcx:'a> {
     tcx: &'a ty::ctxt<'tcx>,
 }
 
-#[allow(dead_code)] // just temporary, for generics
 struct ItemCtxt<'a,'tcx:'a> {
     ccx: &'a CrateCtxt<'a,'tcx>,
     generics: &'a ty::Generics<'tcx>,
@@ -241,6 +240,19 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
         get_trait_def(self.ccx, id)
     }
 
+    fn get_type_parameter_bounds(&self,
+                                 param: subst::ParamSpace,
+                                 index: u32)
+                                 -> Vec<ty::PolyTraitRef<'tcx>>
+    {
+        // TODO out of range indices can occur when you have something
+        // like fn foo<T:U::X,U>() { }
+        match self.generics.types.opt_get(param, index as usize) {
+            Some(def) => def.bounds.trait_bounds.clone(),
+            None => Vec::new(),
+        }
+    }
+
     fn ty_infer(&self, span: Span) -> Ty<'tcx> {
         span_err!(self.tcx().sess, span, E0121,
                   "the type placeholder `_` is not allowed within types on item signatures");
@@ -1596,7 +1608,7 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
     // Now create the real type parameters.
     for (i, param) in types.iter().enumerate() {
-        let def = get_or_create_type_parameter_def(ccx, space, param, i as u32, where_clause);
+        let def = get_or_create_type_parameter_def(ccx, &result, space, param, i as u32);
         debug!("ty_generics: def for type param: {:?}, {:?}", def, space);
         result.types.push(space, def);
     }
@@ -1605,6 +1617,7 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 }
 
 fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
+                                             generics_so_far: &ty::Generics<'tcx>,
                                              space: subst::ParamSpace,
                                              param: &ast::TyParam,
                                              index: u32,
@@ -1619,7 +1632,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
     let param_ty = ty::ParamTy::new(space, index, param.ident.name);
     let bounds = compute_bounds(ccx,
-                                &ty::Generics::empty(),
+                                generics_so_far,
                                 param_ty.to_ty(ccx.tcx),
                                 &param.bounds,
                                 SizedByDefault::Yes,