about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-02-17 20:46:26 -0500
committerNiko Matsakis <niko@alum.mit.edu>2015-02-24 16:27:22 -0500
commit3c782b742bb09d15ccc7bf52bf86091150ba4e5d (patch)
tree47e29321c07c0253f10def481acc2a0baafe7030
parent0d9e473be9e07885d49a7e5699eebd53ccfcc2fb (diff)
downloadrust-3c782b742bb09d15ccc7bf52bf86091150ba4e5d.tar.gz
rust-3c782b742bb09d15ccc7bf52bf86091150ba4e5d.zip
Rework the `get_type_parameter_bounds` impl to use a trait object
and act more generically.
-rw-r--r--src/librustc_typeck/collect.rs110
1 files changed, 79 insertions, 31 deletions
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index cef7f83840b..db5770e4a25 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -150,9 +150,16 @@ struct CrateCtxt<'a,'tcx:'a> {
     stack: RefCell<Vec<AstConvRequest>>,
 }
 
+/// Context specific to some particular item. This is what implements
+/// AstConv. It has information about the predicates that are defined
+/// on the trait. Unfortunately, this predicate information is
+/// available in various different forms at various points in the
+/// process. So we can't just store a pointer to e.g. the AST or the
+/// parsed ty form, we have to wind up keeping both (and making both
+/// optional) and extracting what we need from what's available.
 struct ItemCtxt<'a,'tcx:'a> {
     ccx: &'a CrateCtxt<'a,'tcx>,
-    generics: &'a ty::Generics<'tcx>,
+    param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a),
 }
 
 #[derive(Copy, PartialEq, Eq)]
@@ -216,8 +223,8 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
 // Utility types and common code for the above passes.
 
 impl<'a,'tcx> CrateCtxt<'a,'tcx> {
-    fn icx(&'a self, generics: &'a ty::Generics<'tcx>) -> ItemCtxt<'a,'tcx> {
-        ItemCtxt { ccx: self, generics: generics }
+    fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,'tcx> {
+        ItemCtxt { ccx: self, param_bounds: param_bounds }
     }
 
     fn method_ty(&self, method_id: ast::NodeId) -> Rc<ty::Method<'tcx>> {
@@ -319,11 +326,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
     }
 }
 
-pub trait ToTy<'tcx> {
-    fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>;
-}
-
-impl<'a,'tcx> ToTy<'tcx> for ItemCtxt<'a,'tcx> {
+impl<'a,'tcx> ItemCtxt<'a,'tcx> {
     fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> {
         ast_ty_to_ty(self, rs, ast_ty)
     }
@@ -354,14 +357,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
                                  -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
     {
         self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || {
-            let def = self.tcx().type_parameter_def(node_id);
-
-            // TODO out of range indices can occur when you have something
-            // like fn foo<T:U::X,U>() { }
-            match self.generics.types.opt_get(def.space, def.index as usize) {
-                Some(def) => def.bounds.trait_bounds.clone(),
-                None => Vec::new(),
-            }
+            self.param_bounds.get_type_parameter_bounds(self, span, node_id)
         })
     }
 
@@ -381,6 +377,32 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
     }
 }
 
+
+trait GetTypeParameterBounds<'tcx> {
+    fn get_type_parameter_bounds(&self,
+                                 astconv: &AstConv<'tcx>,
+                                 span: Span,
+                                 node_id: ast::NodeId)
+                                 -> Vec<ty::PolyTraitRef<'tcx>>;
+}
+impl<'tcx> GetTypeParameterBounds<'tcx> for ty::Generics<'tcx> {
+    fn get_type_parameter_bounds(&self,
+                                 astconv: &AstConv<'tcx>,
+                                 _span: Span,
+                                 node_id: ast::NodeId)
+                                 -> Vec<ty::PolyTraitRef<'tcx>>
+    {
+        let def = astconv.tcx().type_parameter_def(node_id);
+
+        // TODO out of range indices can occur when you have something
+        // like fn foo<T:U::X,U>() { }
+        match self.types.opt_get(def.space, def.index as usize) {
+            Some(def) => def.bounds.trait_bounds.clone(),
+            None => Vec::new(),
+        }
+    }
+}
+
 fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                     enum_scheme: ty::TypeScheme<'tcx>,
                                     enum_predicates: ty::GenericPredicates<'tcx>,
@@ -1646,13 +1668,10 @@ fn ty_generic_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                         &ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => {
                             let mut projections = Vec::new();
 
-                            let trait_ref = astconv::instantiate_poly_trait_ref(
-                                &ccx.icx(generics),
-                                &ExplicitRscope,
-                                poly_trait_ref,
-                                Some(ty),
-                                &mut projections,
-                            );
+                            let trait_ref = conv_poly_trait_ref(&ccx.icx(generics),
+                                                                ty,
+                                                                poly_trait_ref,
+                                                                &mut projections);
 
                             result.predicates.push(space, trait_ref.as_predicate());
 
@@ -1934,6 +1953,38 @@ fn check_bounds_compatible<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     }
 }
 
+/// Converts a specific TyParamBound from the AST into the
+/// appropriate poly-trait-reference.
+fn poly_trait_ref_from_bound<'tcx>(astconv: &AstConv<'tcx>,
+                                   param_ty: Ty<'tcx>,
+                                   bound: &ast::TyParamBound,
+                                   projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+                                   -> Option<ty::PolyTraitRef<'tcx>>
+{
+    match *bound {
+        ast::TraitTyParamBound(ref tr, ast::TraitBoundModifier::None) => {
+            Some(conv_poly_trait_ref(astconv, param_ty, tr, projections))
+        }
+        ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) |
+        ast::RegionTyParamBound(_) => {
+            None
+        }
+    }
+}
+
+fn conv_poly_trait_ref<'tcx>(astconv: &AstConv<'tcx>,
+                             param_ty: Ty<'tcx>,
+                             trait_ref: &ast::PolyTraitRef,
+                             projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+                             -> ty::PolyTraitRef<'tcx>
+{
+    astconv::instantiate_poly_trait_ref(astconv,
+                                        &ExplicitRscope,
+                                        trait_ref,
+                                        Some(param_ty),
+                                        projections)
+}
+
 fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                               generics: &ty::Generics<'tcx>,
                               span: Span,
@@ -1952,14 +2003,11 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
     let trait_bounds: Vec<ty::PolyTraitRef> =
         trait_bounds.into_iter()
-        .map(|bound| {
-            astconv::instantiate_poly_trait_ref(&ccx.icx(generics),
-                                                &ExplicitRscope,
-                                                bound,
-                                                Some(param_ty),
-                                                &mut projection_bounds)
-        })
-    .collect();
+                    .map(|bound| conv_poly_trait_ref(&ccx.icx(generics),
+                                                     param_ty,
+                                                     bound,
+                                                     &mut projection_bounds))
+                    .collect();
 
     let region_bounds: Vec<ty::Region> =
         region_bounds.into_iter()