Skip to content

Commit

Permalink
Rollup merge of rust-lang#49427 - Manishearth:rustdoc-impl-trait-exte…
Browse files Browse the repository at this point in the history
…rn, r=GuillaumeGomez

Correctly handle impl trait in external items in rustdoc

fixes rust-lang#49373

r? @QuietMisdreavus
  • Loading branch information
kennytm authored Mar 28, 2018
2 parents c17ab37 + 33dceaa commit 6ca1466
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 10 deletions.
69 changes: 59 additions & 10 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1380,17 +1380,18 @@ fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self
}
}

impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
impl<'a, 'tcx> Clean<TyParamBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
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 {
Expand All @@ -1410,7 +1411,7 @@ impl<'tcx> Clean<TyParamBound> 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,
Expand All @@ -1420,6 +1421,12 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
}
}

impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
fn clean(&self, cx: &DocContext) -> TyParamBound {
(self, vec![]).clean(cx)
}
}

impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
let mut v = Vec::new();
Expand Down Expand Up @@ -2780,9 +2787,51 @@ impl<'tcx> Clean<Type> 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| {
predicate.to_opt_poly_trait_ref().clean(cx)
}).collect())
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;
}
}


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::<Vec<_>>();
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)
Expand Down
37 changes: 37 additions & 0 deletions src/test/rustdoc/auxiliary/extern-impl-trait.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Associated=()> + 'a {
X
}
}

impl Y {
pub fn returns_unsized<'a>(&'a self) -> Box<impl ?Sized + Foo<Associated=()> + 'a> {
Box::new(X)
}
}
21 changes: 21 additions & 0 deletions src/test/rustdoc/extern-impl-trait.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Associated = ()> + 'a"
pub use extern_impl_trait::X;

// @has 'foo/struct.Y.html' '//code' "impl ?Sized + Foo<Associated = ()> + 'a"
pub use extern_impl_trait::Y;

0 comments on commit 6ca1466

Please sign in to comment.