diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6f93c95edef08713d5a625ac8b3a1a46b576e455..bcabefa51fab1eb6b985cf7f9ae5ab5870483659 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -217,8 +217,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, @@ -372,7 +373,9 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option>, 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 9b4803ce41e290718ebb9ef7a609b4cccf5a7564..d3065f16793162ab362d4a8fd6d9b2cc54746d5c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -45,7 +45,7 @@ use std::sync::Arc; use std::u32; -use crate::core::{self, DocContext}; +use crate::core::{self, DocContext, ImplTraitParam}; use crate::doctree; use crate::html::render::{cache, ExternalLocation}; use crate::html::item_type::ItemType; @@ -1540,7 +1540,7 @@ fn clean(&self, cx: &DocContext<'_>) -> 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 { @@ -1552,7 +1552,7 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef { did: self.def_id, bounds: vec![], // These are filled in from the where-clauses. default, - synthetic: None, + synthetic, }) } ty::GenericParamDefKind::Const { .. } => { @@ -1641,7 +1641,7 @@ fn is_impl_trait(param: &hir::GenericParam) -> bool { 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!(), } @@ -1696,25 +1696,76 @@ fn clean(&self, cx: &DocContext<'_>) -> 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() + .filter_map(|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(param.index.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. @@ -2791,7 +2842,7 @@ fn clean(&self, cx: &DocContext<'_>) -> Type { 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); } } @@ -3082,7 +3133,13 @@ fn clean(&self, cx: &DocContext<'_>) -> Type { 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 87381f224d0bb424482d1c6f409599da3a84f81b..592a24fa4ae1a715d8eb7aaade67229d23f1d40c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -61,8 +61,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)`. @@ -459,3 +459,23 @@ fn report_deprecated_attr(name: &str, diag: &errors::Handler) { }) }) } + +/// `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 0000000000000000000000000000000000000000..7807acbc4d61d0ad572a8ad286f3589f43b2834d --- /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 0000000000000000000000000000000000000000..091baa9773ecffe5cae5c682d4a3de2a144cbc92 --- /dev/null +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -0,0 +1,13 @@ +// aux-build:impl_trait_aux.rs + +extern crate impl_trait_aux; + +// @has impl_trait/fn.func.html +// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into> + 'a)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func; + +// @has impl_trait/struct.Foo.html +// @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into> + 'a)" +// @!has - '//code[@id="method.v"]' 'where' +pub use impl_trait_aux::Foo;