mirror of https://github.com/rust-lang/rust.git
Auto merge of #49304 - sinkuu:impl_trait_rustdoc, r=QuietMisdreavus
Rustdoc support for universal_impl_trait Hides type parameters synthesized by `impl Trait`-in-argument-position, and enables links to trait names. <img alt="before" src="https://user-images.githubusercontent.com/7091080/37831646-a61413c6-2ee9-11e8-8ec2-a6137956d922.png" width="450"/> ↓ <img alt="after" src="https://user-images.githubusercontent.com/7091080/37831657-b2ff0ae6-2ee9-11e8-8797-fdad904782bf.png" width="450"/> Fixes #49309
This commit is contained in:
commit
e58df0d8c5
|
@ -1235,6 +1235,7 @@ pub struct TyParam {
|
|||
pub did: DefId,
|
||||
pub bounds: Vec<TyParamBound>,
|
||||
pub default: Option<Type>,
|
||||
pub synthetic: Option<hir::SyntheticTyParamKind>,
|
||||
}
|
||||
|
||||
impl Clean<TyParam> for hir::TyParam {
|
||||
|
@ -1244,6 +1245,7 @@ impl Clean<TyParam> for hir::TyParam {
|
|||
did: cx.tcx.hir.local_def_id(self.id),
|
||||
bounds: self.bounds.clean(cx),
|
||||
default: self.default.clean(cx),
|
||||
synthetic: self.synthetic,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1259,7 +1261,8 @@ impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
|
|||
Some(cx.tcx.type_of(self.def_id).clean(cx))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
synthetic: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1627,6 +1630,16 @@ pub enum GenericParam {
|
|||
Type(TyParam),
|
||||
}
|
||||
|
||||
impl GenericParam {
|
||||
pub fn is_synthetic_type_param(&self) -> bool {
|
||||
if let GenericParam::Type(ref t) = *self {
|
||||
t.synthetic.is_some()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<GenericParam> for hir::GenericParam {
|
||||
fn clean(&self, cx: &DocContext) -> GenericParam {
|
||||
match *self {
|
||||
|
@ -1759,11 +1772,12 @@ pub struct Method {
|
|||
|
||||
impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
|
||||
fn clean(&self, cx: &DocContext) -> Method {
|
||||
let generics = self.1.clean(cx);
|
||||
Method {
|
||||
generics: self.1.clean(cx),
|
||||
decl: enter_impl_trait(cx, &generics.params, || (&*self.0.decl, self.2).clean(cx)),
|
||||
generics,
|
||||
unsafety: self.0.unsafety,
|
||||
constness: self.0.constness,
|
||||
decl: (&*self.0.decl, self.2).clean(cx),
|
||||
abi: self.0.abi
|
||||
}
|
||||
}
|
||||
|
@ -1788,6 +1802,8 @@ pub struct Function {
|
|||
|
||||
impl Clean<Item> for doctree::Function {
|
||||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
let generics = self.generics.clean(cx);
|
||||
let decl = enter_impl_trait(cx, &generics.params, || (&self.decl, self.body).clean(cx));
|
||||
Item {
|
||||
name: Some(self.name.clean(cx)),
|
||||
attrs: self.attrs.clean(cx),
|
||||
|
@ -1797,8 +1813,8 @@ impl Clean<Item> for doctree::Function {
|
|||
deprecation: self.depr.clean(cx),
|
||||
def_id: cx.tcx.hir.local_def_id(self.id),
|
||||
inner: FunctionItem(Function {
|
||||
decl: (&self.decl, self.body).clean(cx),
|
||||
generics: self.generics.clean(cx),
|
||||
decl,
|
||||
generics,
|
||||
unsafety: self.unsafety,
|
||||
constness: self.constness,
|
||||
abi: self.abi,
|
||||
|
@ -1883,7 +1899,8 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
|
|||
vec![].into_iter()
|
||||
} else {
|
||||
cx.tcx.fn_arg_names(did).into_iter()
|
||||
}.peekable();
|
||||
};
|
||||
|
||||
FnDecl {
|
||||
output: Return(sig.skip_binder().output().clean(cx)),
|
||||
attrs: Attributes::default(),
|
||||
|
@ -2025,10 +2042,13 @@ impl Clean<Item> for hir::TraitItem {
|
|||
MethodItem((sig, &self.generics, body).clean(cx))
|
||||
}
|
||||
hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
|
||||
let generics = self.generics.clean(cx);
|
||||
TyMethodItem(TyMethod {
|
||||
unsafety: sig.unsafety.clone(),
|
||||
decl: (&*sig.decl, &names[..]).clean(cx),
|
||||
generics: self.generics.clean(cx),
|
||||
decl: enter_impl_trait(cx, &generics.params, || {
|
||||
(&*sig.decl, &names[..]).clean(cx)
|
||||
}),
|
||||
generics,
|
||||
abi: sig.abi
|
||||
})
|
||||
}
|
||||
|
@ -2532,6 +2552,12 @@ impl Clean<Type> for hir::Ty {
|
|||
return new_ty;
|
||||
}
|
||||
|
||||
if let Def::TyParam(did) = path.def {
|
||||
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
|
||||
return ImplTrait(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
let mut alias = None;
|
||||
if let Def::TyAlias(def_id) = path.def {
|
||||
// Substitute private type aliases
|
||||
|
@ -3244,10 +3270,13 @@ pub struct BareFunctionDecl {
|
|||
|
||||
impl Clean<BareFunctionDecl> for hir::BareFnTy {
|
||||
fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
|
||||
let generic_params = self.generic_params.clean(cx);
|
||||
BareFunctionDecl {
|
||||
unsafety: self.unsafety,
|
||||
generic_params: self.generic_params.clean(cx),
|
||||
decl: (&*self.decl, &self.arg_names[..]).clean(cx),
|
||||
decl: enter_impl_trait(cx, &generic_params, || {
|
||||
(&*self.decl, &self.arg_names[..]).clean(cx)
|
||||
}),
|
||||
generic_params,
|
||||
abi: self.abi,
|
||||
}
|
||||
}
|
||||
|
@ -3548,9 +3577,12 @@ impl Clean<Item> for hir::ForeignItem {
|
|||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
let inner = match self.node {
|
||||
hir::ForeignItemFn(ref decl, ref names, ref generics) => {
|
||||
let generics = generics.clean(cx);
|
||||
ForeignFunctionItem(Function {
|
||||
decl: (&**decl, &names[..]).clean(cx),
|
||||
generics: generics.clean(cx),
|
||||
decl: enter_impl_trait(cx, &generics.params, || {
|
||||
(&**decl, &names[..]).clean(cx)
|
||||
}),
|
||||
generics,
|
||||
unsafety: hir::Unsafety::Unsafe,
|
||||
abi: Abi::Rust,
|
||||
constness: hir::Constness::NotConst,
|
||||
|
@ -3852,6 +3884,29 @@ pub fn def_id_to_path(cx: &DocContext, did: DefId, name: Option<String>) -> Vec<
|
|||
once(crate_name).chain(relative).collect()
|
||||
}
|
||||
|
||||
pub fn enter_impl_trait<F, R>(cx: &DocContext, gps: &[GenericParam], f: F) -> R
|
||||
where
|
||||
F: FnOnce() -> R,
|
||||
{
|
||||
let bounds = gps.iter()
|
||||
.filter_map(|p| {
|
||||
if let GenericParam::Type(ref tp) = *p {
|
||||
if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
|
||||
return Some((tp.did, tp.bounds.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
.collect::<FxHashMap<DefId, Vec<TyParamBound>>>();
|
||||
|
||||
let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), bounds);
|
||||
let r = f();
|
||||
assert!(cx.impl_trait_bounds.borrow().is_empty());
|
||||
*cx.impl_trait_bounds.borrow_mut() = old_bounds;
|
||||
r
|
||||
}
|
||||
|
||||
// Start of code copied from rust-clippy
|
||||
|
||||
pub fn get_trait_def_id(tcx: &TyCtxt, path: &[&str], use_local: bool) -> Option<DefId> {
|
||||
|
|
|
@ -72,6 +72,8 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
|
|||
pub ty_substs: RefCell<FxHashMap<Def, clean::Type>>,
|
||||
/// Table node id of lifetime parameter definition -> substituted lifetime
|
||||
pub lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
|
||||
/// Table DefId of `impl Trait` in argument position -> bounds
|
||||
pub impl_trait_bounds: RefCell<FxHashMap<DefId, Vec<clean::TyParamBound>>>,
|
||||
pub send_trait: Option<DefId>,
|
||||
pub fake_def_ids: RefCell<FxHashMap<CrateNum, DefId>>,
|
||||
pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
|
||||
|
@ -261,6 +263,7 @@ pub fn run_core(search_paths: SearchPaths,
|
|||
renderinfo: Default::default(),
|
||||
ty_substs: Default::default(),
|
||||
lt_substs: Default::default(),
|
||||
impl_trait_bounds: Default::default(),
|
||||
mod_ids: Default::default(),
|
||||
send_trait: send_trait,
|
||||
fake_def_ids: RefCell::new(FxHashMap()),
|
||||
|
|
|
@ -148,11 +148,17 @@ impl fmt::Display for clean::GenericParam {
|
|||
|
||||
impl fmt::Display for clean::Generics {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.params.is_empty() { return Ok(()) }
|
||||
let real_params = self.params
|
||||
.iter()
|
||||
.filter(|p| !p.is_synthetic_type_param())
|
||||
.collect::<Vec<_>>();
|
||||
if real_params.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
if f.alternate() {
|
||||
write!(f, "<{:#}>", CommaSep(&self.params))
|
||||
write!(f, "<{:#}>", CommaSep(&real_params))
|
||||
} else {
|
||||
write!(f, "<{}>", CommaSep(&self.params))
|
||||
write!(f, "<{}>", CommaSep(&real_params))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -575,7 +581,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
|
|||
}
|
||||
many => {
|
||||
primitive_link(f, PrimitiveType::Tuple, "(")?;
|
||||
fmt::Display::fmt(&CommaSep(&many), f)?;
|
||||
fmt::Display::fmt(&CommaSep(many), f)?;
|
||||
primitive_link(f, PrimitiveType::Tuple, ")")
|
||||
}
|
||||
}
|
||||
|
@ -661,18 +667,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
|
|||
}
|
||||
}
|
||||
clean::ImplTrait(ref bounds) => {
|
||||
write!(f, "impl ")?;
|
||||
for (i, bound) in bounds.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, " + ")?;
|
||||
}
|
||||
if f.alternate() {
|
||||
write!(f, "{:#}", *bound)?;
|
||||
} else {
|
||||
write!(f, "{}", *bound)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
write!(f, "impl {}", TyParamBounds(bounds))
|
||||
}
|
||||
clean::QPath { ref name, ref self_type, ref trait_ } => {
|
||||
let should_show_cast = match *trait_ {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// 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.
|
||||
|
||||
#![feature(universal_impl_trait)]
|
||||
#![crate_name = "foo"]
|
||||
|
||||
// @has foo/fn.foo.html
|
||||
// @has - //pre 'foo('
|
||||
// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Clone\.html"'
|
||||
// @matches - '_z: .+impl.+trait\.Copy\.html.+, impl.+trait\.Clone\.html'
|
||||
pub fn foo(_x: impl Clone, _y: i32, _z: (impl Copy, impl Clone)) {
|
||||
}
|
||||
|
||||
pub trait Trait {
|
||||
// @has foo/trait.Trait.html
|
||||
// @has - 'method</a>('
|
||||
// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"'
|
||||
fn method(&self, _x: impl std::fmt::Debug) {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct S<T>(T);
|
||||
|
||||
impl<T> S<T> {
|
||||
// @has foo/struct.S.html
|
||||
// @has - 'bar</a>('
|
||||
// @matches - '_bar: impl <a class="trait" href="[^"]+/trait\.Copy\.html"'
|
||||
pub fn bar(_bar: impl Copy) {
|
||||
}
|
||||
|
||||
// @has - 'baz</a>('
|
||||
// @matches - '_baz:.+struct\.S\.html.+impl .+trait\.Clone\.html'
|
||||
pub fn baz(_baz: S<impl Clone>) {
|
||||
}
|
||||
}
|
||||
|
||||
// @has - 'method</a>('
|
||||
// @matches - '_x: impl <a class="trait" href="[^"]+/trait\.Debug\.html"'
|
||||
impl<T> Trait for S<T> {}
|
Loading…
Reference in New Issue