about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/astconv.rs19
-rw-r--r--src/librustc_typeck/check/mod.rs9
-rw-r--r--src/librustc_typeck/collect.rs37
3 files changed, 52 insertions, 13 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 1e7b90d5a18..e70bef5a44f 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -82,6 +82,9 @@ pub trait AstConv<'tcx> {
     fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId)
                                  -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>;
 
+    fn trait_defines_associated_type_named(&self, trait_def_id: ast::DefId, name: ast::Name)
+                                           -> bool;
+
     /// 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.
@@ -783,7 +786,7 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
     // We want to produce `<B as SuperTrait<int>>::T == foo`.
 
     // Simple case: X is defined in the current trait.
-    if trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) {
+    if this.trait_defines_associated_type_named(trait_ref.def_id, binding.item_name) {
         return Ok(ty::ProjectionPredicate {
             projection_ty: ty::ProjectionTy {
                 trait_ref: trait_ref,
@@ -812,7 +815,7 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
 
     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))
+        .filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name))
         .collect();
 
     // If converting for an object type, then remove the dummy-ty from `Self` now.
@@ -1036,7 +1039,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
 
     let mut suitable_bounds: Vec<_> =
         traits::transitive_bounds(tcx, &bounds)
-        .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
+        .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name))
         .collect();
 
     if suitable_bounds.len() == 0 {
@@ -1090,16 +1093,6 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
     (ty, def::DefAssociatedTy(trait_did, item_did))
 }
 
-fn trait_defines_associated_type_named(this: &AstConv,
-                                       trait_def_id: ast::DefId,
-                                       assoc_name: ast::Name)
-                                       -> bool
-{
-    let tcx = this.tcx();
-    let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
-    trait_def.associated_type_names.contains(&assoc_name)
-}
-
 fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
                      rscope: &RegionScope,
                      span: Span,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a12ff04912c..16cef193e45 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1248,6 +1248,15 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         Ok(r)
     }
 
+    fn trait_defines_associated_type_named(&self,
+                                           trait_def_id: ast::DefId,
+                                           assoc_name: ast::Name)
+                                           -> bool
+    {
+        let trait_def = ty::lookup_trait_def(self.ccx.tcx, trait_def_id);
+        trait_def.associated_type_names.contains(&assoc_name)
+    }
+
     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 74fed6cbf39..1ba49714bcf 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -364,6 +364,19 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
         })
     }
 
+    fn trait_defines_associated_type_named(&self,
+                                           trait_def_id: ast::DefId,
+                                           assoc_name: ast::Name)
+                                           -> bool
+    {
+        if trait_def_id.krate == ast::LOCAL_CRATE {
+            trait_defines_associated_type_named(self.ccx, trait_def_id.node, assoc_name)
+        } else {
+            let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
+            trait_def.associated_type_names.contains(&assoc_name)
+        }
+    }
+
     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");
@@ -1296,6 +1309,30 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
+fn trait_defines_associated_type_named(ccx: &CrateCtxt,
+                                       trait_node_id: ast::NodeId,
+                                       assoc_name: ast::Name)
+                                       -> bool
+{
+    let item = match ccx.tcx.map.get(trait_node_id) {
+        ast_map::NodeItem(item) => item,
+        _ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not an item", trait_node_id))
+    };
+
+    let trait_items = match item.node {
+        ast::ItemTrait(_, _, _, ref trait_items) => trait_items,
+        _ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not a trait", trait_node_id))
+    };
+
+    trait_items.iter()
+               .any(|trait_item| {
+                   match *trait_item {
+                       ast::TypeTraitItem(ref t) => t.ty_param.ident.name == assoc_name,
+                       ast::RequiredMethod(..) | ast::ProvidedMethod(..) => false,
+                   }
+               })
+}
+
 fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) {
     let tcx = ccx.tcx;
     let trait_def = trait_def_of_item(ccx, it);