diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 1436e51f31820..f9d1666977134 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -118,7 +118,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { span: Span::dummy(), unsafety: hir::Unsafety::Normal, generics: new_generics, - trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), + trait_: Some(trait_ref.clean(self.cx)), for_: ty.clean(self.cx), items: Vec::new(), negative_polarity, @@ -166,16 +166,16 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .clone() } - // This method calculates two things: Lifetime constraints of the form 'a: 'b, - // and region constraints of the form ReVar: 'a - // - // This is essentially a simplified version of lexical_region_resolve. However, - // handle_lifetimes determines what *needs be* true in order for an impl to hold. - // lexical_region_resolve, along with much of the rest of the compiler, is concerned - // with determining if a given set up constraints/predicates *are* met, given some - // starting conditions (e.g., user-provided code). For this reason, it's easier - // to perform the calculations we need on our own, rather than trying to make - // existing inference/solver code do what we want. + /// This method calculates two things: Lifetime constraints of the form `'a: 'b`, + /// and region constraints of the form `RegionVid: 'a` + /// + /// This is essentially a simplified version of lexical_region_resolve. However, + /// handle_lifetimes determines what *needs be* true in order for an impl to hold. + /// lexical_region_resolve, along with much of the rest of the compiler, is concerned + /// with determining if a given set up constraints/predicates *are* met, given some + /// starting conditions (e.g., user-provided code). For this reason, it's easier + /// to perform the calculations we need on our own, rather than trying to make + /// existing inference/solver code do what we want. fn handle_lifetimes<'cx>( regions: &RegionConstraintData<'cx>, names_map: &FxHashMap, @@ -353,48 +353,35 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { if let Some(data) = ty_to_fn.get(&ty) { let (poly_trait, output) = (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new)); - let new_ty = match poly_trait.trait_ { - Type::ResolvedPath { ref path, ref did } => { - let mut new_path = path.clone(); - let last_segment = - new_path.segments.pop().expect("segments were empty"); - - let (old_input, old_output) = match last_segment.args { - GenericArgs::AngleBracketed { args, .. } => { - let types = args - .iter() - .filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty.clone()), - _ => None, - }) - .collect(); - (types, None) - } - GenericArgs::Parenthesized { inputs, output, .. } => { - (inputs, output) - } - }; + let mut new_path = poly_trait.trait_.clone(); + let last_segment = new_path.segments.pop().expect("segments were empty"); + + let (old_input, old_output) = match last_segment.args { + GenericArgs::AngleBracketed { args, .. } => { + let types = args + .iter() + .filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty.clone()), + _ => None, + }) + .collect(); + (types, None) + } + GenericArgs::Parenthesized { inputs, output } => (inputs, output), + }; - if old_output.is_some() && old_output != output { - panic!( - "Output mismatch for {:?} {:?} {:?}", - ty, old_output, data.1 - ); - } + if old_output.is_some() && old_output != output { + panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, data.1); + } - let new_params = - GenericArgs::Parenthesized { inputs: old_input, output }; + let new_params = GenericArgs::Parenthesized { inputs: old_input, output }; - new_path - .segments - .push(PathSegment { name: last_segment.name, args: new_params }); + new_path + .segments + .push(PathSegment { name: last_segment.name, args: new_params }); - Type::ResolvedPath { path: new_path, did: *did } - } - _ => panic!("Unexpected data: {:?}, {:?}", ty, data), - }; bounds.insert(GenericBound::TraitBound( - PolyTrait { trait_: new_ty, generic_params: poly_trait.generic_params }, + PolyTrait { trait_: new_path, generic_params: poly_trait.generic_params }, hir::TraitBoundModifier::None, )); } @@ -423,15 +410,15 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .collect() } - // Converts the calculated ParamEnv and lifetime information to a clean::Generics, suitable for - // display on the docs page. Cleaning the Predicates produces sub-optimal `WherePredicate`s, - // so we fix them up: - // - // * Multiple bounds for the same type are coalesced into one: e.g., 'T: Copy', 'T: Debug' - // becomes 'T: Copy + Debug' - // * Fn bounds are handled specially - instead of leaving it as 'T: Fn(), = - // K', we use the dedicated syntax 'T: Fn() -> K' - // * We explicitly add a '?Sized' bound if we didn't find any 'Sized' predicates for a type + /// Converts the calculated `ParamEnv` and lifetime information to a [`clean::Generics`](Generics), suitable for + /// display on the docs page. Cleaning the `Predicates` produces sub-optimal [`WherePredicate`]s, + /// so we fix them up: + /// + /// * Multiple bounds for the same type are coalesced into one: e.g., `T: Copy`, `T: Debug` + /// becomes `T: Copy + Debug` + /// * `Fn` bounds are handled specially - instead of leaving it as `T: Fn(), = + /// K`, we use the dedicated syntax `T: Fn() -> K` + /// * We explicitly add a `?Sized` bound if we didn't find any `Sized` predicates for a type fn param_env_to_generics( &mut self, item_def_id: DefId, @@ -476,7 +463,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let mut has_sized = FxHashSet::default(); let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); - let mut ty_to_traits: FxHashMap> = Default::default(); + let mut ty_to_traits: FxHashMap> = Default::default(); let mut ty_to_fn: FxHashMap, Option)> = Default::default(); @@ -511,11 +498,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { if b.is_sized_bound(self.cx) { has_sized.insert(ty.clone()); } else if !b - .get_trait_type() - .and_then(|t| { + .get_trait_path() + .and_then(|trait_| { ty_to_traits .get(&ty) - .map(|bounds| bounds.contains(&strip_type(t.clone()))) + .map(|bounds| bounds.contains(&strip_path_generics(trait_.clone()))) }) .unwrap_or(false) { @@ -532,7 +519,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // that we don't end up with duplicate bounds (e.g., for<'b, 'b>) for_generics.extend(p.generic_params.clone()); p.generic_params = for_generics.into_iter().collect(); - self.is_fn_ty(&p.trait_) + self.is_fn_trait(&p.trait_) } _ => false, }; @@ -558,78 +545,59 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { match lhs { Type::QPath { name: left_name, ref self_type, ref trait_, .. } => { let ty = &*self_type; - match **trait_ { - Type::ResolvedPath { path: ref trait_path, ref did } => { - let mut new_trait_path = trait_path.clone(); - - if self.is_fn_ty(trait_) && left_name == sym::Output { - ty_to_fn - .entry(*ty.clone()) - .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) - .or_insert((None, Some(rhs))); - continue; - } - - let args = &mut new_trait_path - .segments - .last_mut() - .expect("segments were empty") - .args; - - match args { - // Convert something like ' = u8' - // to 'T: Iterator' - GenericArgs::AngleBracketed { - ref mut bindings, .. - } => { - bindings.push(TypeBinding { - name: left_name, - kind: TypeBindingKind::Equality { ty: rhs }, - }); - } - GenericArgs::Parenthesized { .. } => { - existing_predicates.push(WherePredicate::EqPredicate { - lhs: lhs.clone(), - rhs, - }); - continue; // If something other than a Fn ends up - // with parenthesis, leave it alone - } - } - - let bounds = ty_to_bounds.entry(*ty.clone()).or_default(); - - bounds.insert(GenericBound::TraitBound( - PolyTrait { - trait_: Type::ResolvedPath { - path: new_trait_path, - did: *did, - }, - generic_params: Vec::new(), - }, - hir::TraitBoundModifier::None, - )); - - // Remove any existing 'plain' bound (e.g., 'T: Iterator`) so - // that we don't see a - // duplicate bound like `T: Iterator + Iterator` - // on the docs page. - bounds.remove(&GenericBound::TraitBound( - PolyTrait { - trait_: *trait_.clone(), - generic_params: Vec::new(), - }, - hir::TraitBoundModifier::None, - )); - // Avoid creating any new duplicate bounds later in the outer - // loop - ty_to_traits - .entry(*ty.clone()) - .or_default() - .insert(*trait_.clone()); + let mut new_trait = trait_.clone(); + + if self.is_fn_trait(trait_) && left_name == sym::Output { + ty_to_fn + .entry(*ty.clone()) + .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) + .or_insert((None, Some(rhs))); + continue; + } + + let args = &mut new_trait + .segments + .last_mut() + .expect("segments were empty") + .args; + + match args { + // Convert something like ' = u8' + // to 'T: Iterator' + GenericArgs::AngleBracketed { ref mut bindings, .. } => { + bindings.push(TypeBinding { + name: left_name, + kind: TypeBindingKind::Equality { ty: rhs }, + }); + } + GenericArgs::Parenthesized { .. } => { + existing_predicates.push(WherePredicate::EqPredicate { + lhs: lhs.clone(), + rhs, + }); + continue; // If something other than a Fn ends up + // with parenthesis, leave it alone } - _ => panic!("Unexpected trait {:?} for {:?}", trait_, item_def_id), } + + let bounds = ty_to_bounds.entry(*ty.clone()).or_default(); + + bounds.insert(GenericBound::TraitBound( + PolyTrait { trait_: new_trait, generic_params: Vec::new() }, + hir::TraitBoundModifier::None, + )); + + // Remove any existing 'plain' bound (e.g., 'T: Iterator`) so + // that we don't see a + // duplicate bound like `T: Iterator + Iterator` + // on the docs page. + bounds.remove(&GenericBound::TraitBound( + PolyTrait { trait_: trait_.clone(), generic_params: Vec::new() }, + hir::TraitBoundModifier::None, + )); + // Avoid creating any new duplicate bounds later in the outer + // loop + ty_to_traits.entry(*ty.clone()).or_default().insert(trait_.clone()); } _ => panic!("Unexpected LHS {:?} for {:?}", lhs, item_def_id), } @@ -664,11 +632,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { Generics { params: generic_params, where_predicates: existing_predicates } } - // Ensure that the predicates are in a consistent order. The precise - // ordering doesn't actually matter, but it's important that - // a given set of predicates always appears in the same order - - // both for visual consistency between 'rustdoc' runs, and to - // make writing tests much easier + /// Ensure that the predicates are in a consistent order. The precise + /// ordering doesn't actually matter, but it's important that + /// a given set of predicates always appears in the same order - + /// both for visual consistency between 'rustdoc' runs, and to + /// make writing tests much easier #[inline] fn sort_where_predicates(&self, mut predicates: &mut Vec) { // We should never have identical bounds - and if we do, @@ -677,11 +645,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { self.unstable_debug_sort(&mut predicates); } - // Ensure that the bounds are in a consistent order. The precise - // ordering doesn't actually matter, but it's important that - // a given set of bounds always appears in the same order - - // both for visual consistency between 'rustdoc' runs, and to - // make writing tests much easier + /// Ensure that the bounds are in a consistent order. The precise + /// ordering doesn't actually matter, but it's important that + /// a given set of bounds always appears in the same order - + /// both for visual consistency between 'rustdoc' runs, and to + /// make writing tests much easier #[inline] fn sort_where_bounds(&self, mut bounds: &mut Vec) { // We should never have identical bounds - and if we do, @@ -690,47 +658,43 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { self.unstable_debug_sort(&mut bounds); } - // This might look horrendously hacky, but it's actually not that bad. - // - // For performance reasons, we use several different FxHashMaps - // in the process of computing the final set of where predicates. - // However, the iteration order of a HashMap is completely unspecified. - // In fact, the iteration of an FxHashMap can even vary between platforms, - // since FxHasher has different behavior for 32-bit and 64-bit platforms. - // - // Obviously, it's extremely undesirable for documentation rendering - // to be dependent on the platform it's run on. Apart from being confusing - // to end users, it makes writing tests much more difficult, as predicates - // can appear in any order in the final result. - // - // To solve this problem, we sort WherePredicates and GenericBounds - // by their Debug string. The thing to keep in mind is that we don't really - // care what the final order is - we're synthesizing an impl or bound - // ourselves, so any order can be considered equally valid. By sorting the - // predicates and bounds, however, we ensure that for a given codebase, all - // auto-trait impls always render in exactly the same way. - // - // Using the Debug implementation for sorting prevents us from needing to - // write quite a bit of almost entirely useless code (e.g., how should two - // Types be sorted relative to each other). It also allows us to solve the - // problem for both WherePredicates and GenericBounds at the same time. This - // approach is probably somewhat slower, but the small number of items - // involved (impls rarely have more than a few bounds) means that it - // shouldn't matter in practice. + /// This might look horrendously hacky, but it's actually not that bad. + /// + /// For performance reasons, we use several different FxHashMaps + /// in the process of computing the final set of where predicates. + /// However, the iteration order of a HashMap is completely unspecified. + /// In fact, the iteration of an FxHashMap can even vary between platforms, + /// since FxHasher has different behavior for 32-bit and 64-bit platforms. + /// + /// Obviously, it's extremely undesirable for documentation rendering + /// to be dependent on the platform it's run on. Apart from being confusing + /// to end users, it makes writing tests much more difficult, as predicates + /// can appear in any order in the final result. + /// + /// To solve this problem, we sort WherePredicates and GenericBounds + /// by their Debug string. The thing to keep in mind is that we don't really + /// care what the final order is - we're synthesizing an impl or bound + /// ourselves, so any order can be considered equally valid. By sorting the + /// predicates and bounds, however, we ensure that for a given codebase, all + /// auto-trait impls always render in exactly the same way. + /// + /// Using the Debug implementation for sorting prevents us from needing to + /// write quite a bit of almost entirely useless code (e.g., how should two + /// Types be sorted relative to each other). It also allows us to solve the + /// problem for both WherePredicates and GenericBounds at the same time. This + /// approach is probably somewhat slower, but the small number of items + /// involved (impls rarely have more than a few bounds) means that it + /// shouldn't matter in practice. fn unstable_debug_sort(&self, vec: &mut Vec) { vec.sort_by_cached_key(|x| format!("{:?}", x)) } - fn is_fn_ty(&self, ty: &Type) -> bool { + fn is_fn_trait(&self, path: &Path) -> bool { let tcx = self.cx.tcx; - match ty { - &Type::ResolvedPath { did, .. } => { - did == tcx.require_lang_item(LangItem::Fn, None) - || did == tcx.require_lang_item(LangItem::FnMut, None) - || did == tcx.require_lang_item(LangItem::FnOnce, None) - } - _ => false, - } + let did = path.def_id(); + did == tcx.require_lang_item(LangItem::Fn, None) + || did == tcx.require_lang_item(LangItem::FnMut, None) + || did == tcx.require_lang_item(LangItem::FnOnce, None) } } @@ -741,7 +705,7 @@ fn region_name(region: Region<'_>) -> Option { } } -// Replaces all ReVars in a type with ty::Region's, using the provided map +/// Replaces all [`ty::RegionVid`]s in a type with [`ty::Region`]s, using the provided map. struct RegionReplacer<'a, 'tcx> { vid_to_region: &'a FxHashMap>, tcx: TyCtxt<'tcx>, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 8135d4a2085dd..340d9f311b150 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .clean(self.cx), // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. - trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), + trait_: Some(trait_ref.clean(self.cx)), for_: ty.clean(self.cx), items: self .cx diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4a888b22332ee..ebf61fd104843 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -446,20 +446,26 @@ crate fn build_impl( ), }; let polarity = tcx.impl_polarity(did); - let trait_ = associated_trait.clean(cx).map(|bound| match bound { - clean::GenericBound::TraitBound(polyt, _) => polyt.trait_, - clean::GenericBound::Outlives(..) => unreachable!(), - }); - if trait_.def_id() == tcx.lang_items().deref_trait() { + let trait_ = associated_trait.clean(cx); + if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() { super::build_deref_target_impls(cx, &trait_items, ret); } // Return if the trait itself or any types of the generic parameters are doc(hidden). - let mut stack: Vec<&Type> = trait_.iter().collect(); - stack.push(&for_); + let mut stack: Vec<&Type> = vec![&for_]; + + if let Some(did) = trait_.as_ref().map(|t| t.def_id()) { + if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) { + return; + } + } + if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) { + stack.extend(generics); + } + while let Some(ty) = stack.pop() { if let Some(did) = ty.def_id() { - if cx.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) { + if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) { return; } } @@ -468,14 +474,14 @@ crate fn build_impl( } } - if let Some(trait_did) = trait_.def_id() { - record_extern_trait(cx, trait_did); + if let Some(did) = trait_.as_ref().map(|t| t.def_id()) { + record_extern_trait(cx, did); } let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs); trace!("merged_attrs={:?}", merged_attrs); - trace!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id()); + trace!("build_impl: impl {:?} for {:?}", trait_.as_ref().map(|t| t.def_id()), for_.def_id()); ret.push(clean::Item::from_def_id_and_attrs_and_parts( did, None, @@ -526,7 +532,6 @@ fn build_module( item.ident.name, clean::ImportSource { path: clean::Path { - global: false, res, segments: vec![clean::PathSegment { name: prim_ty.as_sym(), @@ -621,11 +626,10 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: ref mut bounds, .. } if *s == kw::SelfUpper => { - bounds.retain(|bound| match *bound { - clean::GenericBound::TraitBound( - clean::PolyTrait { trait_: clean::ResolvedPath { did, .. }, .. }, - _, - ) => did != trait_did, + bounds.retain(|bound| match bound { + clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => { + trait_.def_id() != trait_did + } _ => true, }); } @@ -633,18 +637,12 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: } } - g.where_predicates.retain(|pred| match *pred { + g.where_predicates.retain(|pred| match pred { clean::WherePredicate::BoundPredicate { - ty: - clean::QPath { - self_type: box clean::Generic(ref s), - trait_: box clean::ResolvedPath { did, .. }, - name: ref _name, - .. - }, - ref bounds, + ty: clean::QPath { self_type: box clean::Generic(ref s), trait_, name: _, .. }, + bounds, .. - } => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did), + } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did), _ => true, }); g diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 49fc93f3feabc..668088bb0a59a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -152,8 +152,8 @@ impl Clean for hir::GenericBound<'_> { } } -impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { - fn clean(&self, cx: &mut DocContext<'_>) -> Type { +impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { + fn clean(&self, cx: &mut DocContext<'_>) -> Path { let (trait_ref, bounds) = *self; let kind = cx.tcx.def_kind(trait_ref.def_id).into(); if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) { @@ -168,16 +168,13 @@ impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); - ResolvedPath { path, did: trait_ref.def_id } + path } } -impl<'tcx> Clean for ty::TraitRef<'tcx> { - fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound { - GenericBound::TraitBound( - PolyTrait { trait_: (*self, &[][..]).clean(cx), generic_params: vec![] }, - hir::TraitBoundModifier::None, - ) +impl Clean for ty::TraitRef<'tcx> { + fn clean(&self, cx: &mut DocContext<'_>) -> Path { + (*self, &[][..]).clean(cx) } } @@ -384,16 +381,13 @@ impl<'tcx> Clean for ty::ProjectionPredicate<'tcx> { impl<'tcx> Clean for ty::ProjectionTy<'tcx> { fn clean(&self, cx: &mut DocContext<'_>) -> Type { let lifted = self.lift_to_tcx(cx.tcx).unwrap(); - let trait_ = match lifted.trait_ref(cx.tcx).clean(cx) { - GenericBound::TraitBound(t, _) => t.trait_, - GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"), - }; + let trait_ = lifted.trait_ref(cx.tcx).clean(cx); let self_type = self.self_ty().clean(cx); Type::QPath { name: cx.tcx.associated_item(self.item_def_id).ident.name, self_def_id: self_type.def_id(), self_type: box self_type, - trait_: box trait_, + trait_, } } } @@ -896,10 +890,11 @@ impl Clean for hir::IsAuto { } } -impl Clean for hir::TraitRef<'_> { - fn clean(&self, cx: &mut DocContext<'_>) -> Type { +impl Clean for hir::TraitRef<'_> { + fn clean(&self, cx: &mut DocContext<'_>) -> Path { let path = self.path.clean(cx); - resolve_type(cx, path) + register_res(cx, path.res); + path } } @@ -1105,9 +1100,8 @@ impl Clean for ty::AssocItem { if *name != my_name { return None; } - match **trait_ { - ResolvedPath { did, .. } if did == self.container.id() => {} - _ => return None, + if trait_.def_id() != self.container.id() { + return None; } match **self_type { Generic(ref s) if *s == kw::SelfUpper => {} @@ -1273,19 +1267,18 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { return normalized_value.clean(cx); } - let segments = if p.is_global() { &p.segments[1..] } else { &p.segments }; - let trait_segments = &segments[..segments.len() - 1]; + let trait_segments = &p.segments[..p.segments.len() - 1]; let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id(); - let trait_path = self::Path { - global: p.is_global(), + let trait_ = self::Path { res: Res::Def(DefKind::Trait, trait_def), segments: trait_segments.clean(cx), }; + register_res(cx, trait_.res); Type::QPath { name: p.segments.last().expect("segments were empty").ident.name, self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)), self_type: box qself.clean(cx), - trait_: box resolve_type(cx, trait_path), + trait_, } } hir::QPath::TypeRelative(ref qself, ref segment) => { @@ -1296,12 +1289,13 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { ty::Error(_) => return Type::Infer, _ => bug!("clean: expected associated type, found `{:?}`", ty), }; - let trait_path = hir::Path { span, res, segments: &[] }.clean(cx); + let trait_ = hir::Path { span, res, segments: &[] }.clean(cx); + register_res(cx, trait_.res); Type::QPath { name: segment.ident.name, self_def_id: res.opt_def_id(), self_type: box qself.clean(cx), - trait_: box resolve_type(cx, trait_path), + trait_, } } hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"), @@ -1470,10 +1464,7 @@ impl<'tcx> Clean for Ty<'tcx> { let empty = cx.tcx.intern_substs(&[]); let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); - let bound = PolyTrait { - trait_: ResolvedPath { path, did }, - generic_params: Vec::new(), - }; + let bound = PolyTrait { trait_: path, generic_params: Vec::new() }; bounds.push(bound); } @@ -1486,10 +1477,7 @@ impl<'tcx> Clean for Ty<'tcx> { } let path = external_path(cx, did, false, bindings, substs); - bounds.insert( - 0, - PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() }, - ); + bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() }); DynTrait(bounds, lifetime) } @@ -1728,11 +1716,7 @@ impl Clean for hir::VariantData<'_> { impl Clean for hir::Path<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Path { - Path { - global: self.is_global(), - res: self.res, - segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx), - } + Path { res: self.res, segments: self.segments.clean(cx) } } } @@ -1898,7 +1882,7 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_> // If this impl block is an implementation of the Deref trait, then we // need to try inlining the target's inherent impl blocks as well. - if trait_.def_id() == tcx.lang_items().deref_trait() { + if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() { build_deref_target_impls(cx, &items, &mut ret); } @@ -1907,7 +1891,7 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_> DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)), _ => None, }); - let mut make_item = |trait_: Option, for_: Type, items: Vec| { + let mut make_item = |trait_: Option, for_: Type, items: Vec| { let kind = ImplItem(Impl { span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx), unsafety: impl_.unsafety, diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 257af6ab91016..4c81e75e8d630 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -99,17 +99,13 @@ crate fn merge_bounds( 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) { + if !trait_is_same_or_supertrait(cx, trait_ref.trait_.def_id(), trait_did) { return false; } - let last = path.segments.last_mut().expect("segments were empty"); + let last = trait_ref.trait_.segments.last_mut().expect("segments were empty"); match last.args { PP::AngleBracketed { ref mut bindings, .. } => { bindings.push(clean::TypeBinding { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 248ff339514ed..2e09768a8ef75 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -120,8 +120,7 @@ crate struct Crate { crate module: Item, crate externs: Vec, crate primitives: ThinVec<(DefId, PrimitiveType)>, - // These are later on moved into `CACHEKEY`, leaving the map empty. - // Only here so that they can be filtered through the rustdoc passes. + /// Only here so that they can be filtered through the rustdoc passes. crate external_traits: Rc>>, crate collapsed: bool, } @@ -1114,7 +1113,7 @@ impl GenericBound { let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( - PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() }, + PolyTrait { trait_: path, generic_params: Vec::new() }, hir::TraitBoundModifier::Maybe, ) } @@ -1122,7 +1121,7 @@ impl GenericBound { crate fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { use rustc_hir::TraitBoundModifier as TBM; if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { - if trait_.def_id() == cx.tcx.lang_items().sized_trait() { + if Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() { return true; } } @@ -1136,7 +1135,7 @@ impl GenericBound { None } - crate fn get_trait_type(&self) -> Option { + crate fn get_trait_path(&self) -> Option { if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { Some(trait_.clone()) } else { @@ -1368,53 +1367,53 @@ crate struct TraitAlias { /// A trait reference, which may have higher ranked lifetimes. #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct PolyTrait { - crate trait_: Type, + crate trait_: Path, crate generic_params: Vec, } -/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original -/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most -/// importantly, it does not preserve mutability or boxes. +/// Rustdoc's representation of types, mostly based on the [`hir::Ty`]. #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate enum Type { - /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). - ResolvedPath { - path: Path, - did: DefId, - }, - /// `dyn for<'a> Trait<'a> + Send + 'static` + /// A named type, which could be a trait. + /// + /// This is mostly Rustdoc's version of [`hir::Path`]. It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics. + ResolvedPath { path: Path, did: DefId }, + /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static` DynTrait(Vec, Option), - /// For parameterized types, so the consumer of the JSON don't go - /// looking for types which don't exist anywhere. + /// A type parameter. Generic(Symbol), - /// Primitives are the fixed-size numeric types (plus int/usize/float), char, - /// arrays, slices, and tuples. + /// A primitive (aka, builtin) type. Primitive(PrimitiveType), - /// `extern "ABI" fn` + /// A function pointer: `extern "ABI" fn(...) -> ...` BareFunction(Box), + /// A tuple type: `(i32, &str)`. Tuple(Vec), + /// A slice type (does *not* include the `&`): `[i32]` Slice(Box), - /// The `String` field is about the size or the constant representing the array's length. + /// An array type. + /// + /// The `String` field is a stringified version of the array's length parameter. Array(Box, String), + /// A raw pointer type: `*const i32`, `*mut i32` RawPointer(Mutability, Box), - BorrowedRef { - lifetime: Option, - mutability: Mutability, - type_: Box, - }, + /// A reference type: `&i32`, `&'a mut Foo` + BorrowedRef { lifetime: Option, mutability: Mutability, type_: Box }, - // `::Name` + /// A qualified path to an associated item: `::Name` QPath { name: Symbol, self_type: Box, + /// FIXME: This is a hack that should be removed; see [this discussion][1]. + /// + /// [1]: https://github.com/rust-lang/rust/pull/85479#discussion_r635729093 self_def_id: Option, - trait_: Box, + trait_: Path, }, - // `_` + /// A type that is inferred: `_` Infer, - // `impl TraitA + TraitB + ...` + /// An `impl Trait`: `impl TraitA + TraitB + ...` ImplTrait(Vec), } @@ -1481,34 +1480,8 @@ impl Type { } crate fn generics(&self) -> Option> { - match *self { - ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { - if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { - Some( - args.iter() - .filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty), - _ => None, - }) - .collect(), - ) - } else { - None - } - }), - _ => None, - } - } - - crate fn bindings(&self) -> Option<&[TypeBinding]> { - match *self { - ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { - if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { - Some(&**bindings) - } else { - None - } - }), + match self { + ResolvedPath { path, .. } => path.generics(), _ => None, } } @@ -1526,17 +1499,13 @@ impl Type { QPath { self_type, trait_, name, .. } => (self_type, trait_, name), _ => return None, }; - let trait_did = match **trait_ { - ResolvedPath { did, .. } => did, - _ => return None, - }; - Some((&self_, trait_did, *name)) + Some((&self_, trait_.def_id(), *name)) } fn inner_def_id(&self, cache: Option<&Cache>) -> Option { let t: PrimitiveType = match *self { ResolvedPath { did, .. } => return Some(did), - DynTrait(ref bounds, _) => return bounds[0].trait_.inner_def_id(cache), + DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()), Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()), BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference, BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache), @@ -1568,8 +1537,12 @@ impl GetDefId for Type { } } -/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't -/// paths, like `Unit`. +/// A primitive (aka, builtin) type. +/// +/// This represents things like `i32`, `str`, etc. +/// +/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't +/// paths, like [`Self::Unit`]. #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] crate enum PrimitiveType { Isize, @@ -1967,12 +1940,15 @@ impl Span { #[derive(Clone, PartialEq, Eq, Debug, Hash)] crate struct Path { - crate global: bool, crate res: Res, crate segments: Vec, } impl Path { + crate fn def_id(&self) -> DefId { + self.res.def_id() + } + crate fn last(&self) -> Symbol { self.segments.last().expect("segments were empty").name } @@ -1982,8 +1958,11 @@ impl Path { } crate fn whole_name(&self) -> String { - String::from(if self.global { "::" } else { "" }) - + &self.segments.iter().map(|s| s.name.to_string()).collect::>().join("::") + self.segments + .iter() + .map(|s| if s.name == kw::PathRoot { String::new() } else { s.name.to_string() }) + .intersperse("::".into()) + .collect() } /// Checks if this is a `T::Name` path for an associated type. @@ -1995,6 +1974,33 @@ impl Path { _ => false, } } + + crate fn generics(&self) -> Option> { + self.segments.last().and_then(|seg| { + if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { + Some( + args.iter() + .filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty), + _ => None, + }) + .collect(), + ) + } else { + None + } + }) + } + + crate fn bindings(&self) -> Option<&[TypeBinding]> { + self.segments.last().and_then(|seg| { + if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { + Some(&**bindings) + } else { + None + } + }) + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] @@ -2138,7 +2144,7 @@ crate struct Impl { crate span: Span, crate unsafety: hir::Unsafety, crate generics: Generics, - crate trait_: Option, + crate trait_: Option, crate for_: Type, crate items: Vec, crate negative_polarity: bool, @@ -2149,7 +2155,8 @@ crate struct Impl { impl Impl { crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet { self.trait_ - .def_id() + .as_ref() + .map(|t| t.def_id()) .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect()) .unwrap_or_default() } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 33d460d587a51..1449b8acf0cd7 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -2,7 +2,7 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, - ItemKind, Lifetime, Path, PathSegment, PolyTrait, Primitive, PrimitiveType, ResolvedPath, Type, + ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding, Visibility, }; use crate::core::DocContext; @@ -148,7 +148,6 @@ pub(super) fn external_path( let def_kind = cx.tcx.def_kind(did); let name = cx.tcx.item_name(did); Path { - global: false, res: Res::Def(def_kind, did), segments: vec![PathSegment { name, @@ -157,39 +156,8 @@ pub(super) fn external_path( } } -crate fn strip_type(ty: Type) -> Type { - match ty { - Type::ResolvedPath { path, did } => Type::ResolvedPath { path: strip_path(&path), did }, - Type::DynTrait(mut bounds, lt) => { - let first = bounds.remove(0); - let stripped_trait = strip_type(first.trait_); - - bounds.insert( - 0, - PolyTrait { trait_: stripped_trait, generic_params: first.generic_params }, - ); - Type::DynTrait(bounds, lt) - } - Type::Tuple(inner_tys) => { - Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect()) - } - Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))), - Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s), - Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))), - Type::BorrowedRef { lifetime, mutability, type_ } => { - Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } - } - Type::QPath { name, self_type, trait_, self_def_id } => Type::QPath { - name, - self_def_id, - self_type: Box::new(strip_type(*self_type)), - trait_: Box::new(strip_type(*trait_)), - }, - _ => ty, - } -} - -crate fn strip_path(path: &Path) -> Path { +/// Remove the generic arguments from a path. +crate fn strip_path_generics(path: Path) -> Path { let segments = path .segments .iter() @@ -199,7 +167,7 @@ crate fn strip_path(path: &Path) -> Path { }) .collect(); - Path { global: path.global, res: path.res, segments } + Path { res: path.res, segments } } crate fn qpath_to_string(p: &hir::QPath<'_>) -> String { diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index bcfcc3d70395c..dd1cf2a866dd4 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -201,7 +201,9 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { // masked crate then remove it completely. if let clean::ImplItem(ref i) = *item.kind { if self.cache.masked_crates.contains(&item.def_id.krate()) - || i.trait_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate)) + || i.trait_ + .as_ref() + .map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate)) || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate)) { return None; @@ -221,11 +223,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { // Collect all the implementors of traits. if let clean::ImplItem(ref i) = *item.kind { - if let Some(did) = i.trait_.def_id() { + if let Some(trait_) = &i.trait_ { if i.blanket_impl.is_none() { self.cache .implementors - .entry(did) + .entry(trait_.def_id()) .or_default() .push(Impl { impl_item: item.clone() }); } @@ -400,12 +402,8 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } clean::DynTrait(ref bounds, _) | clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => { - if let Some(did) = bounds[0].trait_.def_id() { - self.cache.parent_stack.push(did); - true - } else { - false - } + self.cache.parent_stack.push(bounds[0].trait_.def_id()); + true } ref t => { let prim_did = t @@ -439,9 +437,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } clean::DynTrait(ref bounds, _) | clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => { - if let Some(did) = bounds[0].trait_.def_id() { - dids.insert(did); - } + dids.insert(bounds[0].trait_.def_id()); } ref t => { let did = t diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs index 6060b0560cf3c..4f0c5a9edee71 100644 --- a/src/librustdoc/formats/mod.rs +++ b/src/librustdoc/formats/mod.rs @@ -7,14 +7,12 @@ use rustc_hir::def_id::DefId; crate use renderer::{run_format, FormatRenderer}; use crate::clean; -use crate::clean::types::GetDefId; -use crate::formats::cache::Cache; /// Specifies whether rendering directly implemented trait items or ones from a certain Deref /// impl. crate enum AssocItemRender<'a> { All, - DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type, deref_mut_: bool }, + DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, } /// For different handling of associated items from the Deref target of a type rather than the type @@ -40,10 +38,6 @@ impl Impl { } crate fn trait_did(&self) -> Option { - self.inner_impl().trait_.def_id() - } - - crate fn trait_did_full(&self, cache: &Cache) -> Option { - self.inner_impl().trait_.def_id_full(cache) + self.inner_impl().trait_.as_ref().map(|t| t.def_id()) } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index bcd78b2adc085..9cd10481ef03d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,9 +18,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::CRATE_DEF_INDEX; use rustc_target::spec::abi::Abi; -use crate::clean::{ - self, utils::find_nearest_parent_module, ExternalCrate, GetDefId, ItemId, PrimitiveType, -}; +use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType}; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::render::cache::ExternalLocation; @@ -914,15 +912,10 @@ fn fmt_type<'cx>( } } clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => { - let should_show_cast = match *trait_ { - box clean::ResolvedPath { ref path, .. } => { - !path.segments.is_empty() - && self_def_id - .zip(trait_.def_id()) - .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_) - } - _ => true, - }; + let should_show_cast = !trait_.segments.is_empty() + && self_def_id + .zip(Some(trait_.def_id())) + .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_); if f.alternate() { if should_show_cast { write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? @@ -936,36 +929,31 @@ fn fmt_type<'cx>( write!(f, "{}::", self_type.print(cx))? } }; - match *trait_ { - // It's pretty unsightly to look at `::C` in output, and - // we've got hyperlinking on our side, so try to avoid longer - // notation as much as possible by making `C` a hyperlink to trait - // `B` to disambiguate. - // - // FIXME: this is still a lossy conversion and there should probably - // be a better way of representing this in general? Most of - // the ugliness comes from inlining across crates where - // everything comes in as a fully resolved QPath (hard to - // look at). - box clean::ResolvedPath { did, .. } => { - match href(did, cx) { - Ok((ref url, _, ref path)) if !f.alternate() => { - write!( - f, - "::C` in output, and + // we've got hyperlinking on our side, so try to avoid longer + // notation as much as possible by making `C` a hyperlink to trait + // `B` to disambiguate. + // + // FIXME: this is still a lossy conversion and there should probably + // be a better way of representing this in general? Most of + // the ugliness comes from inlining across crates where + // everything comes in as a fully resolved QPath (hard to + // look at). + match href(trait_.def_id(), cx) { + Ok((ref url, _, ref path)) if !f.alternate() => { + write!( + f, + "{name}", - url = url, - shortty = ItemType::AssocType, - name = name, - path = path.join("::") - )?; - } - _ => write!(f, "{}", name)?, - } - Ok(()) + url = url, + shortty = ItemType::AssocType, + name = name, + path = path.join("::") + )?; } - _ => write!(f, "{}", name), + _ => write!(f, "{}", name)?, } + Ok(()) } } } @@ -979,6 +967,15 @@ impl clean::Type { } } +impl clean::Path { + crate fn print<'b, 'a: 'b, 'tcx: 'a>( + &'a self, + cx: &'a Context<'tcx>, + ) -> impl fmt::Display + 'b + Captures<'tcx> { + display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) + } +} + impl clean::Impl { crate fn print<'a, 'tcx: 'a>( &'a self, diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index edd1d8b98fc64..9c05c80d55dfe 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -226,16 +226,13 @@ fn get_index_type(clean_type: &clean::Type) -> RenderType { fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option { match *clean_type { clean::ResolvedPath { ref path, .. } => { - let segments = &path.segments; - let path_segment = segments.iter().last().unwrap_or_else(|| { - panic!( - "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path", - clean_type, accept_generic - ) - }); + let path_segment = path.segments.last().unwrap(); Some(path_segment.name) } - clean::DynTrait(ref bounds, _) => get_index_type_name(&bounds[0].trait_, accept_generic), + clean::DynTrait(ref bounds, _) => { + let path = &bounds[0].trait_; + Some(path.segments.last().unwrap().name) + } clean::Generic(s) if accept_generic => Some(s), clean::Primitive(ref p) => Some(p.as_sym()), clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), @@ -324,7 +321,8 @@ crate fn get_real_types<'tcx>( } if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { for bound in bound.get_bounds().unwrap_or(&[]) { - if let Some(ty) = bound.get_trait_type() { + if let Some(path) = bound.get_trait_path() { + let ty = Type::ResolvedPath { did: path.def_id(), path }; let adds = get_real_types(generics, &ty, tcx, recurse + 1, res); nb_added += adds; if adds == 0 && !ty.is_full_generic() { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 1f27357f6c6ea..6b213da50a79c 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -687,18 +687,12 @@ fn short_item_info( // Render the list of items inside one of the sections "Trait Implementations", // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages). -fn render_impls( - cx: &Context<'_>, - w: &mut Buffer, - traits: &[&&Impl], - containing_item: &clean::Item, -) { - let cache = cx.cache(); +fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_item: &clean::Item) { let tcx = cx.tcx(); - let mut impls = traits + let mut rendered_impls = impls .iter() .map(|i| { - let did = i.trait_did_full(cache).unwrap(); + let did = i.trait_did().unwrap(); let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx); let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods); let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() }; @@ -722,8 +716,8 @@ fn render_impls( buffer.into_inner() }) .collect::>(); - impls.sort(); - w.write_str(&impls.join("")); + rendered_impls.sort(); + w.write_str(&rendered_impls.join("")); } fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String { @@ -1068,13 +1062,11 @@ fn render_assoc_items( return; } if !traits.is_empty() { - let deref_impl = traits.iter().find(|t| { - t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait() - }); + let deref_impl = + traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait()); if let Some(impl_) = deref_impl { - let has_deref_mut = traits.iter().any(|t| { - t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_mut_trait() - }); + let has_deref_mut = + traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait()); render_deref_methods(w, cx, impl_, containing_item, has_deref_mut); } let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = @@ -1192,45 +1184,39 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { let mut out = Buffer::html(); - let mut trait_ = String::new(); if let Some(did) = decl.output.def_id_full(cx.cache()) { if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); - if impl_.trait_.def_id().map_or(false, |d| { - cx.cache().traits.get(&d).map(|t| t.is_notable).unwrap_or(false) - }) { - if out.is_empty() { - write!( - &mut out, - "
Notable traits for {}
\ - ", - impl_.for_.print(cx) - ); - trait_.push_str(&impl_.for_.print(cx).to_string()); - } + if let Some(trait_) = &impl_.trait_ { + let trait_did = trait_.def_id(); - //use the "where" class here to make it small - write!( - &mut out, - "{}", - impl_.print(false, cx) - ); - let t_did = impl_.trait_.def_id_full(cx.cache()).unwrap(); - for it in &impl_.items { - if let clean::TypedefItem(ref tydef, _) = *it.kind { - out.push_str(" "); - assoc_type( + if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable) { + if out.is_empty() { + write!( &mut out, - it, - &[], - Some(&tydef.type_), - AssocItemLink::GotoSource(t_did.into(), &FxHashSet::default()), - "", - cx, + "
Notable traits for {}
\ + ", + impl_.for_.print(cx) ); - out.push_str(";
"); + } + + //use the "where" class here to make it small + write!( + &mut out, + "{}", + impl_.print(false, cx) + ); + for it in &impl_.items { + if let clean::TypedefItem(ref tydef, _) = *it.kind { + out.push_str(" "); + let empty_set = FxHashSet::default(); + let src_link = + AssocItemLink::GotoSource(trait_did.into(), &empty_set); + assoc_type(&mut out, it, &[], Some(&tydef.type_), src_link, "", cx); + out.push_str(";"); + } } } } @@ -1273,7 +1259,7 @@ fn render_impl( ) { let cache = cx.cache(); let traits = &cache.traits; - let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]); + let trait_ = i.trait_did().map(|did| &traits[&did]); let mut close_tags = String::new(); // For trait implementations, the `interesting` output contains all methods that have doc @@ -1503,7 +1489,7 @@ fn render_impl( if i.items.iter().any(|m| m.name == n) { continue; } - let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap(); + let did = i.trait_.as_ref().unwrap().def_id(); let provided_methods = i.provided_trait_methods(cx.tcx()); let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods); @@ -1887,9 +1873,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { } if v.iter().any(|i| i.inner_impl().trait_.is_some()) { - if let Some(impl_) = v.iter().filter(|i| i.inner_impl().trait_.is_some()).find(|i| { - i.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait() - }) { + if let Some(impl_) = + v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait()) + { sidebar_deref_methods(cx, out, impl_, v); } @@ -1987,9 +1973,7 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V } } } - let deref_mut = v.iter().filter(|i| i.inner_impl().trait_.is_some()).any(|i| { - i.inner_impl().trait_.def_id_full(c) == cx.tcx().lang_items().deref_mut_trait() - }); + let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait()); let inner_impl = target .def_id_full(c) .or_else(|| { @@ -2056,10 +2040,10 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea fn get_id_for_impl_on_foreign_type( for_: &clean::Type, - trait_: &clean::Type, + trait_: &clean::Path, cx: &Context<'_>, ) -> String { - small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx),)) + small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx))) } fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> { @@ -2370,6 +2354,15 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { let mut visited = FxHashSet::default(); let mut work = VecDeque::new(); + let mut process_path = |did: DefId| { + let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone()); + let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern); + + if let Some(path) = fqp { + out.push(path.join("::")); + } + }; + work.push_back(first_ty); while let Some(ty) = work.pop_front() { @@ -2378,14 +2371,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { } match ty { - clean::Type::ResolvedPath { did, .. } => { - let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone()); - let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern); - - if let Some(path) = fqp { - out.push(path.join("::")); - } - } + clean::Type::ResolvedPath { did, .. } => process_path(did), clean::Type::Tuple(tys) => { work.extend(tys.into_iter()); } @@ -2403,7 +2389,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { } clean::Type::QPath { self_type, trait_, .. } => { work.push_back(*self_type); - work.push_back(*trait_); + process_path(trait_.def_id()); } _ => {} } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index ea81b041c3bc6..1f2479a302f95 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -363,8 +363,11 @@ impl FromWithTcx for GenericBound { use clean::GenericBound::*; match bound { TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { + // FIXME: should `trait_` be a clean::Path equivalent in JSON? + let trait_ = + clean::ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx); GenericBound::TraitBound { - trait_: trait_.into_tcx(tcx), + trait_, generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), modifier: from_trait_bound_modifier(modifier), } @@ -394,15 +397,12 @@ impl FromWithTcx for Type { param_names: Vec::new(), }, DynTrait(mut bounds, lt) => { - let (path, id) = match bounds.remove(0).trait_ { - ResolvedPath { path, did, .. } => (path, did), - _ => unreachable!(), - }; + let first_trait = bounds.remove(0).trait_; Type::ResolvedPath { - name: path.whole_name(), - id: from_item_id(id.into()), - args: path + name: first_trait.whole_name(), + id: from_item_id(first_trait.def_id().into()), + args: first_trait .segments .last() .map(|args| Box::new(args.clone().args.into_tcx(tcx))), @@ -434,11 +434,15 @@ impl FromWithTcx for Type { mutable: mutability == ast::Mutability::Mut, type_: Box::new((*type_).into_tcx(tcx)), }, - QPath { name, self_type, trait_, .. } => Type::QualifiedPath { - name: name.to_string(), - self_type: Box::new((*self_type).into_tcx(tcx)), - trait_: Box::new((*trait_).into_tcx(tcx)), - }, + QPath { name, self_type, trait_, .. } => { + // FIXME: should `trait_` be a clean::Path equivalent in JSON? + let trait_ = ResolvedPath { did: trait_.def_id(), path: trait_ }.into_tcx(tcx); + Type::QualifiedPath { + name: name.to_string(), + self_type: Box::new((*self_type).into_tcx(tcx)), + trait_: Box::new(trait_), + } + } } } } @@ -507,6 +511,11 @@ impl FromWithTcx for Impl { blanket_impl, span: _span, } = impl_; + // FIXME: should `trait_` be a clean::Path equivalent in JSON? + let trait_ = trait_.map(|path| { + let did = path.def_id(); + clean::ResolvedPath { path, did }.into_tcx(tcx) + }); Impl { is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, generics: generics.into_tcx(tcx), @@ -514,7 +523,7 @@ impl FromWithTcx for Impl { .into_iter() .map(|x| x.to_string()) .collect(), - trait_: trait_.map(|x| x.into_tcx(tcx)), + trait_, for_: for_.into_tcx(tcx), items: ids(items), negative: negative_polarity, diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index eefe50caa345e..319dd7b42b0ee 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -57,7 +57,9 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { // scan through included items ahead of time to splice in Deref targets to the "valid" sets for it in &new_items { if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind { - if cleaner.keep_impl(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() { + if cleaner.keep_impl(for_) + && trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait() + { let target = items .iter() .find_map(|item| match *item.kind { @@ -78,7 +80,9 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { new_items.retain(|it| { if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind { cleaner.keep_impl(for_) - || trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t)) + || trait_ + .as_ref() + .map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into())) || blanket_impl.is_some() } else { true diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 90300dbd16b13..8b1fd662f85fd 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -134,7 +134,7 @@ impl<'a> DocFolder for ImplStripper<'a> { return None; } } - if let Some(did) = imp.trait_.def_id() { + if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) { if did.is_local() && !self.retained.contains(&did.into()) { debug!("ImplStripper: impl item for stripped trait; removing"); return None;