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>, 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 `>::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 = 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);