From ae10e478eb61e75ebf3a7bf672b34b582555fd8e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 26 May 2015 17:12:39 +0300 Subject: [PATCH 1/4] Implement defaults for associated types --- src/librustc/metadata/decoder.rs | 35 ++++++---- src/librustc/metadata/encoder.rs | 23 ++++--- src/librustc/middle/traits/project.rs | 50 +++++++------- src/librustc/middle/ty.rs | 5 +- src/librustc/util/ppaux.rs | 2 +- src/librustc_typeck/check/mod.rs | 17 ++--- src/librustc_typeck/collect.rs | 48 ++++++------- src/librustdoc/clean/inline.rs | 8 ++- src/librustdoc/clean/mod.rs | 69 +++++++++---------- src/test/run-pass/default-associated-types.rs | 30 ++++++++ 10 files changed, 167 insertions(+), 120 deletions(-) create mode 100644 src/test/run-pass/default-associated-types.rs diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 42dcc9661ca2d..5eefb99b058f1 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -252,6 +252,13 @@ fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> |_, did| translate_def_id(cdata, did)) } +fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option> { + reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| { + parse_ty_data(tp.data, cdata.cnum, tp.start, tcx, + |_, did| translate_def_id(cdata, did)) + }) +} + fn doc_method_fty<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> ty::BareFnTy<'tcx> { let tp = reader::get_doc(doc, tag_item_method_fty); @@ -875,24 +882,24 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) -> ty::ImplOrTraitItem<'tcx> { - let method_doc = lookup_item(id, cdata.data()); + let item_doc = lookup_item(id, cdata.data()); - let def_id = item_def_id(method_doc, cdata); + let def_id = item_def_id(item_doc, cdata); - let container_id = item_require_parent_item(cdata, method_doc); + let container_id = item_require_parent_item(cdata, item_doc); let container_doc = lookup_item(container_id.node, cdata.data()); let container = match item_family(container_doc) { Trait => TraitContainer(container_id), _ => ImplContainer(container_id), }; - let name = item_name(&*intr, method_doc); - let vis = item_visibility(method_doc); + let name = item_name(&*intr, item_doc); + let vis = item_visibility(item_doc); - match item_sort(method_doc) { + match item_sort(item_doc) { Some('C') => { - let ty = doc_type(method_doc, tcx, cdata); - let default = get_provided_source(method_doc, cdata); + let ty = doc_type(item_doc, tcx, cdata); + let default = get_provided_source(item_doc, cdata); ty::ConstTraitItem(Rc::new(ty::AssociatedConst { name: name, ty: ty, @@ -903,11 +910,11 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, })) } Some('r') | Some('p') => { - let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics); - let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics); - let fty = doc_method_fty(method_doc, tcx, cdata); - let explicit_self = get_explicit_self(method_doc); - let provided_source = get_provided_source(method_doc, cdata); + let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics); + let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics); + let fty = doc_method_fty(item_doc, tcx, cdata); + let explicit_self = get_explicit_self(item_doc); + let provided_source = get_provided_source(item_doc, cdata); ty::MethodTraitItem(Rc::new(ty::Method::new(name, generics, @@ -920,8 +927,10 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, provided_source))) } Some('t') => { + let ty = maybe_doc_type(item_doc, tcx, cdata); ty::TypeTraitItem(Rc::new(ty::AssociatedType { name: name, + ty: ty, vis: vis, def_id: def_id, container: container, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 0908ffd249fe4..8eefb4d5011d2 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -894,12 +894,12 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } -fn encode_info_for_associated_type(ecx: &EncodeContext, - rbml_w: &mut Encoder, - associated_type: &ty::AssociatedType, - impl_path: PathElems, - parent_id: NodeId, - impl_item_opt: Option<&ast::ImplItem>) { +fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + associated_type: &ty::AssociatedType<'tcx>, + impl_path: PathElems, + parent_id: NodeId, + impl_item_opt: Option<&ast::ImplItem>) { debug!("encode_info_for_associated_type({:?},{:?})", associated_type.def_id, token::get_name(associated_type.name)); @@ -913,8 +913,6 @@ fn encode_info_for_associated_type(ecx: &EncodeContext, encode_parent_item(rbml_w, local_def(parent_id)); encode_item_sort(rbml_w, 't'); - encode_bounds_and_type_for_item(rbml_w, ecx, associated_type.def_id.local_id()); - let stab = stability::lookup(ecx.tcx, associated_type.def_id); encode_stability(rbml_w, stab); @@ -923,7 +921,14 @@ fn encode_info_for_associated_type(ecx: &EncodeContext, if let Some(ii) = impl_item_opt { encode_attributes(rbml_w, &ii.attrs); - encode_type(ecx, rbml_w, ty::node_id_to_type(ecx.tcx, ii.id)); + } else { + encode_predicates(rbml_w, ecx, + &ty::lookup_predicates(ecx.tcx, associated_type.def_id), + tag_item_generics); + } + + if let Some(ty) = associated_type.ty { + encode_type(ecx, rbml_w, ty); } rbml_w.end_tag(); diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index f6bde80e29875..700aaad8b72d3 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -857,37 +857,39 @@ fn confirm_impl_candidate<'cx,'tcx>( -> (Ty<'tcx>, Vec>) { // there don't seem to be nicer accessors to these: - let impl_items_map = selcx.tcx().impl_items.borrow(); let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow(); - let impl_items = impl_items_map.get(&impl_vtable.impl_def_id).unwrap(); - let mut impl_ty = None; - for impl_item in impl_items { - let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() { - ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(), - ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; } - }; - - if assoc_type.name != obligation.predicate.item_name { - continue; + for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] { + if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] { + if assoc_ty.name == obligation.predicate.item_name { + return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs), + impl_vtable.nested.into_vec()); + } } - - let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id); - impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs)); - break; } - match impl_ty { - Some(ty) => (ty, impl_vtable.nested.into_vec()), - None => { - // This means that the impl is missing a - // definition for the associated type. This error - // ought to be reported by the type checker method - // `check_impl_items_against_trait`, so here we - // just return ty_err. - (selcx.tcx().types.err, vec!()) + let trait_ref = obligation.predicate.trait_ref; + for trait_item in ty::trait_items(selcx.tcx(), trait_ref.def_id).iter() { + if let &ty::TypeTraitItem(ref assoc_ty) = trait_item { + if assoc_ty.name == obligation.predicate.item_name { + if let Some(ty) = assoc_ty.ty { + return (ty.subst(selcx.tcx(), trait_ref.substs), + impl_vtable.nested.into_vec()); + } else { + // This means that the impl is missing a + // definition for the associated type. This error + // ought to be reported by the type checker method + // `check_impl_items_against_trait`, so here we + // just return ty_err. + return (selcx.tcx().types.err, vec!()); + } + } } } + + selcx.tcx().sess.span_bug(obligation.cause.span, + &format!("No associated type for {}", + trait_ref.repr(selcx.tcx()))); } impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2ccbb0c5c103e..a67a968ea2cf9 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -136,7 +136,7 @@ impl ImplOrTraitItemContainer { pub enum ImplOrTraitItem<'tcx> { ConstTraitItem(Rc>), MethodTraitItem(Rc>), - TypeTraitItem(Rc), + TypeTraitItem(Rc>), } impl<'tcx> ImplOrTraitItem<'tcx> { @@ -267,8 +267,9 @@ pub struct AssociatedConst<'tcx> { } #[derive(Clone, Copy, Debug)] -pub struct AssociatedType { +pub struct AssociatedType<'tcx> { pub name: ast::Name, + pub ty: Option>, pub vis: ast::Visibility, pub def_id: ast::DefId, pub container: ImplOrTraitItemContainer, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index cf2911ab182ef..6f71def11886d 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1077,7 +1077,7 @@ impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> { } } -impl<'tcx> Repr<'tcx> for ty::AssociatedType { +impl<'tcx> Repr<'tcx> for ty::AssociatedType<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("AssociatedType(name: {}, vis: {}, def_id: {})", self.name.repr(tcx), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eb6e90414e3fd..05aad1d64f729 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1070,7 +1070,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Check for missing items from trait let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id); let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id); - let mut missing_methods = Vec::new(); + let mut missing_items = Vec::new(); for trait_item in &*trait_items { match *trait_item { ty::ConstTraitItem(ref associated_const) => { @@ -1086,8 +1086,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, associated_consts.iter().any(|ac| ac.default.is_some() && ac.name == associated_const.name); if !is_implemented && !is_provided { - missing_methods.push(format!("`{}`", - token::get_name(associated_const.name))); + missing_items.push(format!("`{}`", + token::get_name(associated_const.name))); } } ty::MethodTraitItem(ref trait_method) => { @@ -1103,7 +1103,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let is_provided = provided_methods.iter().any(|m| m.name == trait_method.name); if !is_implemented && !is_provided { - missing_methods.push(format!("`{}`", token::get_name(trait_method.name))); + missing_items.push(format!("`{}`", token::get_name(trait_method.name))); } } ty::TypeTraitItem(ref associated_type) => { @@ -1115,17 +1115,18 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, _ => false, } }); - if !is_implemented { - missing_methods.push(format!("`{}`", token::get_name(associated_type.name))); + let is_provided = associated_type.ty.is_some(); + if !is_implemented && !is_provided { + missing_items.push(format!("`{}`", token::get_name(associated_type.name))); } } } } - if !missing_methods.is_empty() { + if !missing_items.is_empty() { span_err!(tcx.sess, impl_span, E0046, "not all trait items implemented, missing: {}", - missing_methods.connect(", ")); + missing_items.connect(", ")); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2fba967b3b237..6507f6dc37242 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -718,15 +718,17 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .insert(local_def(id), ty::ConstTraitItem(associated_const)); } -fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - ident: ast::Ident, - id: ast::NodeId, - vis: ast::Visibility) +fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + container: ImplOrTraitItemContainer, + ident: ast::Ident, + id: ast::NodeId, + vis: ast::Visibility, + ty: Option>) { let associated_type = Rc::new(ty::AssociatedType { name: ident.name, vis: vis, + ty: ty, def_id: local_def(id), container: container }); @@ -876,21 +878,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { if let ast::TypeImplItem(ref ty) = impl_item.node { if opt_trait_ref.is_none() { span_err!(tcx.sess, impl_item.span, E0202, - "associated items are not allowed in inherent impls"); + "associated types are not allowed in inherent impls"); } - as_refsociated_type(ccx, ImplContainer(local_def(it.id)), - impl_item.ident, impl_item.id, impl_item.vis); - let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); - tcx.tcache.borrow_mut().insert(local_def(impl_item.id), - TypeScheme { - generics: ty::Generics::empty(), - ty: typ, - }); - tcx.predicates.borrow_mut().insert(local_def(impl_item.id), - ty::GenericPredicates::empty()); - write_ty_to_tcx(tcx, impl_item.id, typ); + + convert_associated_type(ccx, ImplContainer(local_def(it.id)), + impl_item.ident, impl_item.id, impl_item.vis, + Some(typ)); } } @@ -973,9 +968,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { // Convert all the associated types. for trait_item in trait_items { match trait_item.node { - ast::TypeTraitItem(..) => { - as_refsociated_type(ccx, TraitContainer(local_def(it.id)), - trait_item.ident, trait_item.id, ast::Public); + ast::TypeTraitItem(_, ref opt_ty) => { + let typ = opt_ty.as_ref().map({ + |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) + }); + + convert_associated_type(ccx, TraitContainer(local_def(it.id)), + trait_item.ident, trait_item.id, ast::Public, + typ); } _ => {} } @@ -2292,10 +2292,10 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, let lifetimes_in_associated_types: HashSet<_> = impl_items.iter() - .filter_map(|item| match item.node { - ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)), - ast::ConstImplItem(..) | ast::MethodImplItem(..) | - ast::MacImplItem(..) => None, + .map(|item| ty::impl_or_trait_item(tcx, local_def(item.id))) + .filter_map(|item| match item { + ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, + ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None }) .flat_map(|ty| ctp::parameters_for_type(ty).into_iter()) .filter_map(|p| match p { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9c64b7b4ab623..fcc4e5bb96c88 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -362,11 +362,13 @@ pub fn build_impl(cx: &DocContext, } ty::TypeTraitItem(ref assoc_ty) => { let did = assoc_ty.def_id; - let type_scheme = ty::lookup_item_type(tcx, did); - let predicates = ty::lookup_predicates(tcx, did); + let type_scheme = ty::TypeScheme { + ty: assoc_ty.ty.unwrap(), + generics: ty::Generics::empty() + }; // Not sure the choice of ParamSpace actually matters here, // because an associated type won't have generics on the LHS - let typedef = (type_scheme, predicates, + let typedef = (type_scheme, ty::GenericPredicates::empty(), subst::ParamSpace::TypeSpace).clean(cx); Some(clean::Item { name: Some(assoc_ty.name.clean(cx)), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 95444bb915872..b5aa27d0b0394 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2724,43 +2724,40 @@ impl<'tcx> Clean for ty::AssociatedConst<'tcx> { } } -impl Clean for ty::AssociatedType { +impl<'tcx> Clean for ty::AssociatedType<'tcx> { fn clean(&self, cx: &DocContext) -> Item { - // When loading a cross-crate associated type, the bounds for this type - // are actually located on the trait/impl itself, so we need to load - // all of the generics from there and then look for bounds that are - // applied to this associated type in question. - let predicates = ty::lookup_predicates(cx.tcx(), self.container.id()); - let generics = match self.container { - ty::TraitContainer(did) => { - let def = ty::lookup_trait_def(cx.tcx(), did); - (&def.generics, &predicates, subst::TypeSpace).clean(cx) - } - ty::ImplContainer(did) => { - let ty = ty::lookup_item_type(cx.tcx(), did); - (&ty.generics, &predicates, subst::TypeSpace).clean(cx) - } - }; let my_name = self.name.clean(cx); - let mut bounds = generics.where_predicates.iter().filter_map(|pred| { - let (name, self_type, trait_, bounds) = match *pred { - WherePredicate::BoundPredicate { - ty: QPath { ref name, ref self_type, ref trait_ }, - ref bounds - } => (name, self_type, trait_, bounds), - _ => return None, - }; - if *name != my_name { return None } - match **trait_ { - ResolvedPath { did, .. } if did == self.container.id() => {} - _ => return None, - } - match **self_type { - Generic(ref s) if *s == "Self" => {} - _ => return None, - } - Some(bounds) - }).flat_map(|i| i.iter().cloned()).collect::>(); + + let mut bounds = if let ty::TraitContainer(did) = self.container { + // When loading a cross-crate associated type, the bounds for this type + // are actually located on the trait/impl itself, so we need to load + // all of the generics from there and then look for bounds that are + // applied to this associated type in question. + let def = ty::lookup_trait_def(cx.tcx(), did); + let predicates = ty::lookup_predicates(cx.tcx(), did); + let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); + generics.where_predicates.iter().filter_map(|pred| { + let (name, self_type, trait_, bounds) = match *pred { + WherePredicate::BoundPredicate { + ty: QPath { ref name, ref self_type, ref trait_ }, + ref bounds + } => (name, self_type, trait_, bounds), + _ => return None, + }; + if *name != my_name { return None } + match **trait_ { + ResolvedPath { did, .. } if did == self.container.id() => {} + _ => return None, + } + match **self_type { + Generic(ref s) if *s == "Self" => {} + _ => return None, + } + Some(bounds) + }).flat_map(|i| i.iter().cloned()).collect::>() + } else { + vec![] + }; // Our Sized/?Sized bound didn't get handled when creating the generics // because we didn't actually get our whole set of bounds until just now @@ -2776,7 +2773,7 @@ impl Clean for ty::AssociatedType { source: DUMMY_SP.clean(cx), name: Some(self.name.clean(cx)), attrs: inline::load_attrs(cx, cx.tcx(), self.def_id), - inner: AssociatedTypeItem(bounds, None), + inner: AssociatedTypeItem(bounds, self.ty.clean(cx)), visibility: self.vis.clean(cx), def_id: self.def_id, stability: stability::lookup(cx.tcx(), self.def_id).clean(cx), diff --git a/src/test/run-pass/default-associated-types.rs b/src/test/run-pass/default-associated-types.rs new file mode 100644 index 0000000000000..b3def429b9b8c --- /dev/null +++ b/src/test/run-pass/default-associated-types.rs @@ -0,0 +1,30 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + type Out = T; + fn foo(&self) -> Self::Out; +} + +impl Foo for () { + fn foo(&self) -> u32 { + 4u32 + } +} + +impl Foo for bool { + type Out = (); + fn foo(&self) {} +} + +fn main() { + assert_eq!(<() as Foo>::foo(&()), 4u32); + assert_eq!(>::foo(&true), ()); +} From 65a3245319405e4dd53f10abdbc042502d184c93 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 26 May 2015 20:01:20 +0300 Subject: [PATCH 2/4] Add tests for fixed issues Fixes #23037. Fixes #25339. --- src/test/compile-fail/issue-23073.rs | 17 +++++++++++++ src/test/run-pass/issue-25339.rs | 36 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/test/compile-fail/issue-23073.rs create mode 100644 src/test/run-pass/issue-25339.rs diff --git a/src/test/compile-fail/issue-23073.rs b/src/test/compile-fail/issue-23073.rs new file mode 100644 index 0000000000000..1286ba873be5a --- /dev/null +++ b/src/test/compile-fail/issue-23073.rs @@ -0,0 +1,17 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { type T; } +trait Bar { + type Foo: Foo; + type FooT = <::Foo>::T; //~ ERROR ambiguous associated type +} + +fn main() {} diff --git a/src/test/run-pass/issue-25339.rs b/src/test/run-pass/issue-25339.rs new file mode 100644 index 0000000000000..af172000fdb1a --- /dev/null +++ b/src/test/run-pass/issue-25339.rs @@ -0,0 +1,36 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker::PhantomData; + +pub trait Routing { + type Output; + fn resolve(&self, input: I); +} + +pub trait ToRouting { + type Input; + type Routing : ?Sized = Routing; + fn to_routing(self) -> Self::Routing; +} + +pub struct Mount> { + action: R, + _marker: PhantomData +} + +impl> Mount { + pub fn create>(mount: &str, input: T) { + input.to_routing(); + } +} + +fn main() { +} From c68e65251c86ffdb21aecec56ec45e303d952d79 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 27 May 2015 20:31:56 +0300 Subject: [PATCH 3/4] test fixes --- src/test/compile-fail/assoc-inherent.rs | 2 +- src/test/compile-fail/issue-22673.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/assoc-inherent.rs b/src/test/compile-fail/assoc-inherent.rs index e68c3e30b9a7b..7eab831258f2e 100644 --- a/src/test/compile-fail/assoc-inherent.rs +++ b/src/test/compile-fail/assoc-inherent.rs @@ -13,7 +13,7 @@ struct Foo; impl Foo { - type Bar = isize; //~ERROR associated items are not allowed in inherent impls + type Bar = isize; //~ERROR associated types are not allowed in inherent impls } fn main() {} diff --git a/src/test/compile-fail/issue-22673.rs b/src/test/compile-fail/issue-22673.rs index 6983d1f0706a0..442e6bcda5a09 100644 --- a/src/test/compile-fail/issue-22673.rs +++ b/src/test/compile-fail/issue-22673.rs @@ -10,7 +10,7 @@ trait Expr : PartialEq { //~^ ERROR: unsupported cyclic reference between types/traits detected - type Item = Expr; + type Item; } fn main() {} From 699fc80780b50d302a74475ff9240995d8117516 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 27 May 2015 20:42:42 +0300 Subject: [PATCH 4/4] Address review comments --- src/librustc/middle/traits/project.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 700aaad8b72d3..969f82cc5ae1b 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -859,6 +859,7 @@ fn confirm_impl_candidate<'cx,'tcx>( // there don't seem to be nicer accessors to these: let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow(); + // Look for the associated type in the impl for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] { if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] { if assoc_ty.name == obligation.predicate.item_name { @@ -868,6 +869,7 @@ fn confirm_impl_candidate<'cx,'tcx>( } } + // It is not in the impl - get the default from the trait. let trait_ref = obligation.predicate.trait_ref; for trait_item in ty::trait_items(selcx.tcx(), trait_ref.def_id).iter() { if let &ty::TypeTraitItem(ref assoc_ty) = trait_item {