diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9259b3b5d3abb..b023369bfe9dc 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -210,8 +210,9 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { }; let predicates = cx.tcx.predicates_of(did); - let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); - let decl = (did, sig).clean(cx); + let (generics, decl) = clean::enter_impl_trait(cx, || { + ((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx)) + }); let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx); clean::Function { decl, @@ -347,7 +348,9 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec) { None } }).collect::>(), - (tcx.generics_of(did), &predicates).clean(cx), + clean::enter_impl_trait(cx, || { + (tcx.generics_of(did), &predicates).clean(cx) + }), ) }; let polarity = tcx.impl_polarity(did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 41a56756a1480..b5fcecf39413e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -47,7 +47,7 @@ use std::u32; use parking_lot::ReentrantMutex; -use crate::core::{self, DocContext}; +use crate::core::{self, DocContext, ImplTraitParam}; use crate::doctree; use crate::visit_ast; use crate::html::render::{cache, ExternalLocation}; @@ -1536,7 +1536,7 @@ impl Clean for ty::GenericParamDef { ty::GenericParamDefKind::Lifetime => { (self.name.to_string(), GenericParamDefKind::Lifetime) } - ty::GenericParamDefKind::Type { has_default, .. } => { + ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { cx.renderinfo.borrow_mut().external_param_names .insert(self.def_id, self.name.clean(cx)); let default = if has_default { @@ -1548,7 +1548,7 @@ impl Clean for ty::GenericParamDef { did: self.def_id, bounds: vec![], // These are filled in from the where-clauses. default, - synthetic: None, + synthetic, }) } ty::GenericParamDefKind::Const { .. } => { @@ -1637,7 +1637,7 @@ impl Clean for hir::Generics { match param.kind { GenericParamDefKind::Lifetime => unreachable!(), GenericParamDefKind::Type { did, ref bounds, .. } => { - cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone()); + cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone()); } GenericParamDefKind::Const { .. } => unreachable!(), } @@ -1692,25 +1692,76 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, let (gens, preds) = *self; + // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses, + // since `Clean for ty::Predicate` would consume them. + let mut impl_trait = FxHashMap::>::default(); + // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_typeck::collect::ty_generics), so remove // them. - let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => None, - ty::GenericParamDefKind::Type { .. } => { - if param.name.as_symbol() == kw::SelfUpper { - assert_eq!(param.index, 0); - return None; + let stripped_typarams = gens.params.iter().enumerate() + .filter_map(|(i, param)| match param.kind { + ty::GenericParamDefKind::Lifetime => None, + ty::GenericParamDefKind::Type { synthetic, .. } => { + if param.name.as_symbol() == kw::SelfUpper { + assert_eq!(param.index, 0); + return None; + } + if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { + impl_trait.insert((i as u32).into(), vec![]); + return None; + } + Some(param.clean(cx)) } - Some(param.clean(cx)) - } - ty::GenericParamDefKind::Const { .. } => None, - }).collect::>(); + ty::GenericParamDefKind::Const { .. } => None, + }).collect::>(); let mut where_predicates = preds.predicates.iter() - .flat_map(|(p, _)| p.clean(cx)) + .flat_map(|(p, _)| { + let param_idx = if let Some(trait_ref) = p.to_opt_poly_trait_ref() { + if let ty::Param(param) = trait_ref.self_ty().sty { + Some(param.index) + } else { + None + } + } else if let Some(outlives) = p.to_opt_type_outlives() { + if let ty::Param(param) = outlives.skip_binder().0.sty { + Some(param.index) + } else { + None + } + } else { + None + }; + + let p = p.clean(cx)?; + + if let Some(b) = param_idx.and_then(|i| impl_trait.get_mut(&i.into())) { + b.extend( + p.get_bounds() + .into_iter() + .flatten() + .cloned() + .filter(|b| !b.is_sized_bound(cx)) + ); + return None; + } + + Some(p) + }) .collect::>(); + // Move `TraitPredicate`s to the front. + for (_, bounds) in impl_trait.iter_mut() { + bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b { + false + } else { + true + }); + } + + cx.impl_trait_bounds.borrow_mut().extend(impl_trait); + // Type parameters and have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with // a Sized bound, removing the bounds as we find them. @@ -2789,7 +2840,7 @@ impl Clean for hir::Ty { if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() { return new_ty; } - if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) { + if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) { return ImplTrait(bounds); } } @@ -3079,7 +3130,13 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Projection(ref data) => data.clean(cx), - ty::Param(ref p) => Generic(p.name.to_string()), + ty::Param(ref p) => { + if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) { + ImplTrait(bounds) + } else { + Generic(p.name.to_string()) + } + } ty::Opaque(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7da501ef6cb74..ec834c373da4f 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -65,8 +65,8 @@ pub struct DocContext<'tcx> { pub lt_substs: RefCell>, /// Table `DefId` of const parameter -> substituted const pub ct_substs: RefCell>, - /// Table DefId of `impl Trait` in argument position -> bounds - pub impl_trait_bounds: RefCell>>, + /// Table synthetic type parameter for `impl Trait` in argument position -> bounds + pub impl_trait_bounds: RefCell>>, pub fake_def_ids: RefCell>, pub all_fake_def_ids: RefCell>, /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. @@ -472,3 +472,23 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }) }) } + +/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter +/// for `impl Trait` in argument position. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum ImplTraitParam { + DefId(DefId), + ParamIndex(u32), +} + +impl From for ImplTraitParam { + fn from(did: DefId) -> Self { + ImplTraitParam::DefId(did) + } +} + +impl From for ImplTraitParam { + fn from(idx: u32) -> Self { + ImplTraitParam::ParamIndex(idx) + } +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs new file mode 100644 index 0000000000000..7807acbc4d61d --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -0,0 +1,7 @@ +pub fn func<'a>(_x: impl Clone + Into> + 'a) {} + +pub struct Foo; + +impl Foo { + pub fn method<'a>(_x: impl Clone + Into> + 'a) {} +} diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs new file mode 100644 index 0000000000000..02c49145c762e --- /dev/null +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -0,0 +1,19 @@ +// aux-build:impl_trait_aux.rs + +extern crate impl_trait_aux; + +// @has impl_trait/fn.func.html +// @has - '//pre[@class="rust fn"]' '(_x: impl ' +// @has - '//pre[@class="rust fn"]' 'Clone' +// @has - '//pre[@class="rust fn"]' 'Into' +// @has - '//pre[@class="rust fn"]' "'a" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func; + +// @has impl_trait/struct.Foo.html +// @has - '//code[@id="method.v"]' '(_x: impl ' +// @has - '//code[@id="method.v"]' 'Clone' +// @has - '//code[@id="method.v"]' 'Into' +// @has - '//code[@id="method.v"]' "'a" +// @!has - '//code[@id="method.v"]' 'where' +pub use impl_trait_aux::Foo;