From 37fa6f8b12b9bcbd8fb663a6c1a6c5b98aa052fe Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 27 Mar 2018 14:18:54 +0200 Subject: [PATCH 1/5] rustdoc: Don't use into_iter() when cleaning impl Trait --- src/librustdoc/clean/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1a42b02140cd2..b4c78df741528 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2756,7 +2756,7 @@ impl<'tcx> Clean for Ty<'tcx> { let predicates_of = cx.tcx.predicates_of(def_id); let substs = cx.tcx.lift(&substs).unwrap(); let bounds = predicates_of.instantiate(cx.tcx, substs); - ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| { + ImplTrait(bounds.predicates.iter().filter_map(|predicate| { predicate.to_opt_poly_trait_ref().clean(cx) }).collect()) } From ac655d25c7c1b56fb70b272890b5df1cdd43d236 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 27 Mar 2018 20:45:24 +0200 Subject: [PATCH 2/5] rustdoc: Include associated type bounds when cleaning foreign impl traits --- src/librustdoc/clean/mod.rs | 46 ++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b4c78df741528..875ed12718fa3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1379,17 +1379,18 @@ fn external_path(cx: &DocContext, name: &str, trait_did: Option, has_self } } -impl<'tcx> Clean for ty::TraitRef<'tcx> { +impl<'a, 'tcx> Clean for (&'a ty::TraitRef<'tcx>, Vec) { fn clean(&self, cx: &DocContext) -> TyParamBound { - inline::record_extern_fqn(cx, self.def_id, TypeKind::Trait); - let path = external_path(cx, &cx.tcx.item_name(self.def_id), - Some(self.def_id), true, vec![], self.substs); + let (trait_ref, ref bounds) = *self; + inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait); + let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id), + Some(trait_ref.def_id), true, bounds.clone(), trait_ref.substs); - debug!("ty::TraitRef\n subst: {:?}\n", self.substs); + debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); // collect any late bound regions let mut late_bounds = vec![]; - for ty_s in self.input_types().skip(1) { + for ty_s in trait_ref.input_types().skip(1) { if let ty::TyTuple(ts) = ty_s.sty { for &ty_s in ts { if let ty::TyRef(ref reg, _) = ty_s.sty { @@ -1409,7 +1410,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { trait_: ResolvedPath { path, typarams: None, - did: self.def_id, + did: trait_ref.def_id, is_generic: false, }, generic_params: late_bounds, @@ -1419,6 +1420,12 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { } } +impl<'tcx> Clean for ty::TraitRef<'tcx> { + fn clean(&self, cx: &DocContext) -> TyParamBound { + (self, vec![]).clean(cx) + } +} + impl<'tcx> Clean>> for Substs<'tcx> { fn clean(&self, cx: &DocContext) -> Option> { let mut v = Vec::new(); @@ -2757,7 +2764,30 @@ impl<'tcx> Clean for Ty<'tcx> { let substs = cx.tcx.lift(&substs).unwrap(); let bounds = predicates_of.instantiate(cx.tcx, substs); ImplTrait(bounds.predicates.iter().filter_map(|predicate| { - predicate.to_opt_poly_trait_ref().clean(cx) + let trait_ref = if let Some(tr) = predicate.to_opt_poly_trait_ref() { + tr + } else { + return None; + }; + + let bounds = bounds.predicates.iter().filter_map(|pred| + if let ty::Predicate::Projection(proj) = *pred { + let proj = proj.skip_binder(); + if proj.projection_ty.trait_ref(cx.tcx) == *trait_ref.skip_binder() { + Some(TypeBinding { + name: cx.tcx.associated_item(proj.projection_ty.item_def_id) + .name.clean(cx), + ty: proj.ty.clean(cx), + }) + } else { + None + } + } else { + None + } + ).collect(); + + Some((trait_ref.skip_binder(), bounds).clean(cx)) }).collect()) } From 32446f8db3586ff8c56b745bc2fbaf4c88bcab71 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 27 Mar 2018 20:59:09 +0200 Subject: [PATCH 3/5] rustdoc: Remove Sized bounds when cleaning foreign impl Trait --- src/librustdoc/clean/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 875ed12718fa3..aa8a7fc534627 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2770,6 +2770,14 @@ impl<'tcx> Clean for Ty<'tcx> { return None; }; + if let Some(sized) = cx.tcx.lang_items().sized_trait() { + if trait_ref.def_id() == sized { + return None; + } + } + + // FIXME(Manishearth) handle cases which aren't Sized + let bounds = bounds.predicates.iter().filter_map(|pred| if let ty::Predicate::Projection(proj) = *pred { let proj = proj.skip_binder(); From 6a547b4f61f7acec8bf526e93cc244a82cb8925e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 27 Mar 2018 21:26:44 +0200 Subject: [PATCH 4/5] rustdoc: Handle explicit ?Sized on foreign impl Trait --- src/librustdoc/clean/mod.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index aa8a7fc534627..a7d34d5252434 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2763,20 +2763,26 @@ impl<'tcx> Clean for Ty<'tcx> { let predicates_of = cx.tcx.predicates_of(def_id); let substs = cx.tcx.lift(&substs).unwrap(); let bounds = predicates_of.instantiate(cx.tcx, substs); - ImplTrait(bounds.predicates.iter().filter_map(|predicate| { + let mut regions = vec![]; + let mut has_sized = false; + let mut bounds = bounds.predicates.iter().filter_map(|predicate| { let trait_ref = if let Some(tr) = predicate.to_opt_poly_trait_ref() { tr + } else if let ty::Predicate::TypeOutlives(pred) = *predicate { + // these should turn up at the end + pred.skip_binder().1.clean(cx).map(|r| regions.push(RegionBound(r))); + return None; } else { return None; }; if let Some(sized) = cx.tcx.lang_items().sized_trait() { if trait_ref.def_id() == sized { + has_sized = true; return None; } } - // FIXME(Manishearth) handle cases which aren't Sized let bounds = bounds.predicates.iter().filter_map(|pred| if let ty::Predicate::Projection(proj) = *pred { @@ -2796,7 +2802,12 @@ impl<'tcx> Clean for Ty<'tcx> { ).collect(); Some((trait_ref.skip_binder(), bounds).clean(cx)) - }).collect()) + }).collect::>(); + bounds.extend(regions); + if !has_sized && !bounds.is_empty() { + bounds.insert(0, TyParamBound::maybe_sized(cx)); + } + ImplTrait(bounds) } ty::TyClosure(..) | ty::TyGenerator(..) => Tuple(vec![]), // FIXME(pcwalton) From 33dceaa24409951dfe7607c580de6fd504932c90 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 27 Mar 2018 21:37:27 +0200 Subject: [PATCH 5/5] rustdoc: Add test for foreign impl trait with bounds --- .../rustdoc/auxiliary/extern-impl-trait.rs | 37 +++++++++++++++++++ src/test/rustdoc/extern-impl-trait.rs | 21 +++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/test/rustdoc/auxiliary/extern-impl-trait.rs create mode 100644 src/test/rustdoc/extern-impl-trait.rs diff --git a/src/test/rustdoc/auxiliary/extern-impl-trait.rs b/src/test/rustdoc/auxiliary/extern-impl-trait.rs new file mode 100644 index 0000000000000..ba6c3e956953b --- /dev/null +++ b/src/test/rustdoc/auxiliary/extern-impl-trait.rs @@ -0,0 +1,37 @@ +// Copyright 2018 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. + +pub trait Foo { + type Associated; +} + +pub struct X; +pub struct Y; + + +impl Foo for X { + type Associated = (); +} + +impl Foo for Y { + type Associated = (); +} + +impl X { + pub fn returns_sized<'a>(&'a self) -> impl Foo + 'a { + X + } +} + +impl Y { + pub fn returns_unsized<'a>(&'a self) -> Box + 'a> { + Box::new(X) + } +} diff --git a/src/test/rustdoc/extern-impl-trait.rs b/src/test/rustdoc/extern-impl-trait.rs new file mode 100644 index 0000000000000..02a8e962fe17b --- /dev/null +++ b/src/test/rustdoc/extern-impl-trait.rs @@ -0,0 +1,21 @@ +// Copyright 2018 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. + +// aux-build:extern-impl-trait.rs + +#![crate_name = "foo"] + +extern crate extern_impl_trait; + +// @has 'foo/struct.X.html' '//code' "impl Foo + 'a" +pub use extern_impl_trait::X; + +// @has 'foo/struct.Y.html' '//code' "impl ?Sized + Foo + 'a" +pub use extern_impl_trait::Y;