From b78367d8e8c3273b2cdeefc4ce55897e08e592b2 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Fri, 21 Jun 2019 12:23:05 +0900 Subject: [PATCH 1/6] Support `impl Trait` in inlined documentation --- src/librustdoc/clean/inline.rs | 9 +- src/librustdoc/clean/mod.rs | 91 +++++++++++++++---- src/librustdoc/core.rs | 24 ++++- .../inline_cross/auxiliary/impl_trait_aux.rs | 7 ++ src/test/rustdoc/inline_cross/impl_trait.rs | 13 +++ 5 files changed, 122 insertions(+), 22 deletions(-) create mode 100644 src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs create mode 100644 src/test/rustdoc/inline_cross/impl_trait.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6f93c95edef08..bcabefa51fab1 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 9b4803ce41e29..d3065f1679316 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -45,7 +45,7 @@ use std::cell::RefCell; 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 @@ 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 { @@ -1552,7 +1552,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 { .. } => { @@ -1641,7 +1641,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!(), } @@ -1696,25 +1696,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() + .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 @@ 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); } } @@ -3082,7 +3133,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 87381f224d0bb..592a24fa4ae1a 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 @@ 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..091baa9773ecf --- /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; From 9beff38382a88ceafcb6e83636535c07eacad345 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Mon, 8 Jul 2019 17:59:26 +0900 Subject: [PATCH 2/6] Associated type bound for inlined impl Trait doc --- src/librustdoc/clean/mod.rs | 93 +++++++++++++----- src/librustdoc/clean/simplify.rs | 96 ++++++++++--------- .../inline_cross/auxiliary/impl_trait_aux.rs | 4 + src/test/rustdoc/inline_cross/impl_trait.rs | 6 ++ 4 files changed, 131 insertions(+), 68 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d3065f1679316..bde1826c7fd5a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1698,7 +1698,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, // 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(); + 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 @@ -1720,41 +1720,73 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericParamDefKind::Const { .. } => None, }).collect::>(); + // (param index, def id of trait) -> (name, type) + let mut impl_trait_proj = FxHashMap::<(u32, DefId), Vec<(String, Type)>>::default(); + let mut where_predicates = preds.predicates.iter() .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 + let param_idx = (|| { + if let Some(trait_ref) = p.to_opt_poly_trait_ref() { + if let ty::Param(param) = trait_ref.self_ty().sty { + return Some(param.index); + } + } else if let Some(outlives) = p.to_opt_type_outlives() { + if let ty::Param(param) = outlives.skip_binder().0.sty { + return Some(param.index); + } + } else if let ty::Predicate::Projection(proj) = p { + if let ty::Param(param) = proj.skip_binder().projection_ty.self_ty().sty { + return Some(param.index); + } } - } 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; + if let Some(param_idx) = param_idx { + if let Some(b) = impl_trait.get_mut(¶m_idx.into()) { + b.extend( + p.get_bounds() + .into_iter() + .flatten() + .cloned() + .filter(|b| !b.is_sized_bound(cx)) + ); + + let proj = match &p { + WherePredicate::EqPredicate { lhs, rhs } => Some((lhs, rhs)) + .and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))), + _ => None, + }; + if let Some(((_, trait_did, name), rhs)) = proj { + impl_trait_proj + .entry((param_idx, trait_did)) + .or_default() + .push((name.to_string(), rhs.clone())); + } + + return None; + } } Some(p) }) .collect::>(); + for ((param_idx, trait_did), bounds) in impl_trait_proj { + for (name, rhs) in bounds { + simplify::merge_bounds( + cx, + impl_trait.get_mut(¶m_idx.into()).unwrap(), + trait_did, + &name, + &rhs, + ); + } + } + // Move `TraitPredicate`s to the front. for (_, bounds) in impl_trait.iter_mut() { bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b { @@ -2664,6 +2696,21 @@ impl Type { _ => false, } } + + pub fn projection(&self) -> Option<(&Type, DefId, &str)> { + let (self_, trait_, name) = match self { + QPath { ref self_type, ref trait_, ref name } => { + (self_type, trait_, name) + } + _ => return None, + }; + let trait_did = match **trait_ { + ResolvedPath { did, .. } => did, + _ => return None, + }; + Some((&self_, trait_did, name)) + } + } impl GetDefId for Type { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 3801c42307fc6..8758ab1969116 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -53,58 +53,21 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { // Look for equality predicates on associated types that can be merged into // general bound predicates equalities.retain(|&(ref lhs, ref rhs)| { - let (self_, trait_, name) = match *lhs { - clean::QPath { ref self_type, ref trait_, ref name } => { - (self_type, trait_, name) - } - _ => return true, - }; - let generic = match **self_ { - clean::Generic(ref s) => s, - _ => return true, + let (self_, trait_did, name) = if let Some(p) = lhs.projection() { + p + } else { + return true; }; - let trait_did = match **trait_ { - clean::ResolvedPath { did, .. } => did, + let generic = match self_ { + clean::Generic(s) => s, _ => return true, }; let bounds = match params.get_mut(generic) { Some(bound) => bound, None => return true, }; - !bounds.iter_mut().any(|b| { - let trait_ref = match *b { - clean::GenericBound::TraitBound(ref mut tr, _) => tr, - clean::GenericBound::Outlives(..) => return false, - }; - let (did, path) = match trait_ref.trait_ { - clean::ResolvedPath { did, ref mut path, ..} => (did, path), - _ => return false, - }; - // If this QPath's trait `trait_did` is the same as, or a supertrait - // of, the bound's trait `did` then we can keep going, otherwise - // this is just a plain old equality bound. - if !trait_is_same_or_supertrait(cx, did, trait_did) { - return false - } - let last = path.segments.last_mut().expect("segments were empty"); - match last.args { - PP::AngleBracketed { ref mut bindings, .. } => { - bindings.push(clean::TypeBinding { - name: name.clone(), - kind: clean::TypeBindingKind::Equality { - ty: rhs.clone(), - }, - }); - } - PP::Parenthesized { ref mut output, .. } => { - assert!(output.is_none()); - if *rhs != clean::Type::Tuple(Vec::new()) { - *output = Some(rhs.clone()); - } - } - }; - true - }) + + merge_bounds(cx, bounds, trait_did, name, rhs) }); // And finally, let's reassemble everything @@ -127,6 +90,49 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { clauses } +pub fn merge_bounds( + cx: &clean::DocContext<'_>, + bounds: &mut Vec, + trait_did: DefId, + name: &str, + rhs: &clean::Type, +) -> bool { + !bounds.iter_mut().any(|b| { + let trait_ref = match *b { + clean::GenericBound::TraitBound(ref mut tr, _) => tr, + clean::GenericBound::Outlives(..) => return false, + }; + let (did, path) = match trait_ref.trait_ { + clean::ResolvedPath { did, ref mut path, ..} => (did, path), + _ => return false, + }; + // If this QPath's trait `trait_did` is the same as, or a supertrait + // of, the bound's trait `did` then we can keep going, otherwise + // this is just a plain old equality bound. + if !trait_is_same_or_supertrait(cx, did, trait_did) { + return false + } + let last = path.segments.last_mut().expect("segments were empty"); + match last.args { + PP::AngleBracketed { ref mut bindings, .. } => { + bindings.push(clean::TypeBinding { + name: name.to_string(), + kind: clean::TypeBindingKind::Equality { + ty: rhs.clone(), + }, + }); + } + PP::Parenthesized { ref mut output, .. } => { + assert!(output.is_none()); + if *rhs != clean::Type::Tuple(Vec::new()) { + *output = Some(rhs.clone()); + } + } + }; + true + }) +} + pub fn ty_params(mut params: Vec) -> Vec { for param in &mut params { match param.kind { diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs index 7807acbc4d61d..7b6e665b85f19 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -1,5 +1,9 @@ +use std::ops::Deref; + pub fn func<'a>(_x: impl Clone + Into> + 'a) {} +pub fn func2(_x: impl Deref> + Iterator, _y: impl Iterator) {} + pub struct Foo; impl Foo { diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs index 091baa9773ecf..20d193aad16dc 100644 --- a/src/test/rustdoc/inline_cross/impl_trait.rs +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -7,6 +7,12 @@ extern crate impl_trait_aux; // @!has - '//pre[@class="rust fn"]' 'where' pub use impl_trait_aux::func; +// @has impl_trait/fn.func2.html +// @has - '//pre[@class="rust fn"]' "_x: impl Deref> + Iterator," +// @has - '//pre[@class="rust fn"]' "_y: impl Iterator)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func2; + // @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' From 5f9e26382f3d8a1a90f866d1089e74ab9cf5b152 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Mon, 8 Jul 2019 20:42:45 +0900 Subject: [PATCH 3/6] Support nested `impl Trait` --- src/librustdoc/clean/mod.rs | 58 +++++++++++-------- .../inline_cross/auxiliary/impl_trait_aux.rs | 2 + src/test/rustdoc/inline_cross/impl_trait.rs | 6 ++ 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bde1826c7fd5a..93e650d6d61ae 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1720,11 +1720,13 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericParamDefKind::Const { .. } => None, }).collect::>(); - // (param index, def id of trait) -> (name, type) - let mut impl_trait_proj = FxHashMap::<(u32, DefId), Vec<(String, Type)>>::default(); + // param index -> [(DefId of trait, associated type name, type)] + let mut impl_trait_proj = + FxHashMap::)>>::default(); let mut where_predicates = preds.predicates.iter() .flat_map(|(p, _)| { + let mut projection = None; let param_idx = (|| { if let Some(trait_ref) = p.to_opt_poly_trait_ref() { if let ty::Param(param) = trait_ref.self_ty().sty { @@ -1734,8 +1736,9 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, if let ty::Param(param) = outlives.skip_binder().0.sty { return Some(param.index); } - } else if let ty::Predicate::Projection(proj) = p { - if let ty::Param(param) = proj.skip_binder().projection_ty.self_ty().sty { + } else if let ty::Predicate::Projection(p) = p { + if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().sty { + projection = Some(p); return Some(param.index); } } @@ -1755,16 +1758,15 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, .filter(|b| !b.is_sized_bound(cx)) ); - let proj = match &p { - WherePredicate::EqPredicate { lhs, rhs } => Some((lhs, rhs)) - .and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))), - _ => None, - }; - if let Some(((_, trait_did, name), rhs)) = proj { + let proj = projection + .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty)); + if let Some(((_, trait_did, name), rhs)) = + proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))) + { impl_trait_proj - .entry((param_idx, trait_did)) + .entry(param_idx) .or_default() - .push((name.to_string(), rhs.clone())); + .push((trait_did, name.to_string(), rhs)); } return None; @@ -1775,18 +1777,6 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, }) .collect::>(); - for ((param_idx, trait_did), bounds) in impl_trait_proj { - for (name, rhs) in bounds { - simplify::merge_bounds( - cx, - impl_trait.get_mut(¶m_idx.into()).unwrap(), - trait_did, - &name, - &rhs, - ); - } - } - // Move `TraitPredicate`s to the front. for (_, bounds) in impl_trait.iter_mut() { bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b { @@ -1796,7 +1786,25 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, }); } - cx.impl_trait_bounds.borrow_mut().extend(impl_trait); + for (param, mut bounds) in impl_trait { + if let crate::core::ImplTraitParam::ParamIndex(idx) = param { + if let Some(proj) = impl_trait_proj.remove(&idx) { + for (trait_did, name, rhs) in proj { + simplify::merge_bounds( + cx, + &mut bounds, + trait_did, + &name, + &rhs.clean(cx), + ); + } + } + } else { + unreachable!(); + } + + cx.impl_trait_bounds.borrow_mut().insert(param, bounds); + } // Type parameters and have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs index 7b6e665b85f19..e0f7c6d08ce2f 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -4,6 +4,8 @@ pub fn func<'a>(_x: impl Clone + Into> + 'a) {} pub fn func2(_x: impl Deref> + Iterator, _y: impl Iterator) {} +pub fn func3(_x: impl Iterator> + Clone) {} + pub struct Foo; impl Foo { diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs index 20d193aad16dc..b08a070dcb74d 100644 --- a/src/test/rustdoc/inline_cross/impl_trait.rs +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -8,11 +8,17 @@ extern crate impl_trait_aux; pub use impl_trait_aux::func; // @has impl_trait/fn.func2.html +// @has - '//pre[@class="rust fn"]' "func2(" // @has - '//pre[@class="rust fn"]' "_x: impl Deref> + Iterator," // @has - '//pre[@class="rust fn"]' "_y: impl Iterator)" // @!has - '//pre[@class="rust fn"]' 'where' pub use impl_trait_aux::func2; +// @has impl_trait/fn.func3.html +// @has - '//pre[@class="rust fn"]' "func3(_x: impl Clone + Iterator>)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func3; + // @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' From cc6dbb4f237ae0d84db5994cd075065efe05306b Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Mon, 8 Jul 2019 20:45:59 +0900 Subject: [PATCH 4/6] Fix tidy --- src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs | 5 ++++- src/test/rustdoc/inline_cross/impl_trait.rs | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs index e0f7c6d08ce2f..24efe4297103f 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -2,7 +2,10 @@ use std::ops::Deref; pub fn func<'a>(_x: impl Clone + Into> + 'a) {} -pub fn func2(_x: impl Deref> + Iterator, _y: impl Iterator) {} +pub fn func2( + _x: impl Deref> + Iterator, + _y: impl Iterator, +) {} pub fn func3(_x: impl Iterator> + Clone) {} diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs index b08a070dcb74d..3a9f2f880798d 100644 --- a/src/test/rustdoc/inline_cross/impl_trait.rs +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -15,7 +15,8 @@ pub use impl_trait_aux::func; pub use impl_trait_aux::func2; // @has impl_trait/fn.func3.html -// @has - '//pre[@class="rust fn"]' "func3(_x: impl Clone + Iterator>)" +// @has - '//pre[@class="rust fn"]' "func3(" +// @has - '//pre[@class="rust fn"]' "_x: impl Clone + Iterator>)" // @!has - '//pre[@class="rust fn"]' 'where' pub use impl_trait_aux::func3; From 3620456fafa04505c23511aa07d34f704ee7c84b Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Tue, 9 Jul 2019 16:37:55 +0900 Subject: [PATCH 5/6] Use BTreeMap for deterministic iter order --- src/librustdoc/clean/mod.rs | 9 ++++----- src/librustdoc/core.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 93e650d6d61ae..37ee79aa9e4f1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1693,12 +1693,13 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, &'a &'tcx ty::GenericPredicates<'tcx>) { fn clean(&self, cx: &DocContext<'_>) -> Generics { use self::WherePredicate as WP; + use std::collections::BTreeMap; 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(); + let mut impl_trait = BTreeMap::>::default(); // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_typeck::collect::ty_generics), so remove @@ -1777,16 +1778,14 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, }) .collect::>(); - // Move `TraitPredicate`s to the front. - for (_, bounds) in impl_trait.iter_mut() { + for (param, mut bounds) in impl_trait { + // Move trait bounds to the front. bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b { false } else { true }); - } - for (param, mut bounds) in impl_trait { if let crate::core::ImplTraitParam::ParamIndex(idx) = param { if let Some(proj) = impl_trait_proj.remove(&idx) { for (trait_did, name, rhs) in proj { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 592a24fa4ae1a..04e69613d4b0f 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -462,7 +462,7 @@ 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)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ImplTraitParam { DefId(DefId), ParamIndex(u32), From 1fe6160c7e4b584795c66f21683064f62803acf0 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Tue, 9 Jul 2019 16:59:34 +0900 Subject: [PATCH 6/6] Fix ICE with `impl Trait` in type bounds --- src/librustdoc/clean/mod.rs | 13 ++++++++++--- .../inline_cross/auxiliary/impl_trait_aux.rs | 2 ++ src/test/rustdoc/inline_cross/impl_trait.rs | 6 ++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 37ee79aa9e4f1..ba792a413b3c4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1725,7 +1725,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, let mut impl_trait_proj = FxHashMap::)>>::default(); - let mut where_predicates = preds.predicates.iter() + let where_predicates = preds.predicates.iter() .flat_map(|(p, _)| { let mut projection = None; let param_idx = (|| { @@ -1747,10 +1747,10 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, None })(); - let p = p.clean(cx)?; - if let Some(param_idx) = param_idx { if let Some(b) = impl_trait.get_mut(¶m_idx.into()) { + let p = p.clean(cx)?; + b.extend( p.get_bounds() .into_iter() @@ -1805,6 +1805,13 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, cx.impl_trait_bounds.borrow_mut().insert(param, bounds); } + // Now that `cx.impl_trait_bounds` is populated, we can process + // remaining predicates which could contain `impl Trait`. + let mut where_predicates = where_predicates + .into_iter() + .flat_map(|p| p.clean(cx)) + .collect::>(); + // 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. diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs index 24efe4297103f..21c733a9bc98e 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -9,6 +9,8 @@ pub fn func2( pub fn func3(_x: impl Iterator> + Clone) {} +pub fn func4>(_x: T) {} + pub struct Foo; impl Foo { diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs index 3a9f2f880798d..b1e3f8d145b5f 100644 --- a/src/test/rustdoc/inline_cross/impl_trait.rs +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -20,6 +20,12 @@ pub use impl_trait_aux::func2; // @!has - '//pre[@class="rust fn"]' 'where' pub use impl_trait_aux::func3; + +// @has impl_trait/fn.func4.html +// @has - '//pre[@class="rust fn"]' "func4(" +// @has - '//pre[@class="rust fn"]' "T: Iterator," +pub use impl_trait_aux::func4; + // @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'